blob: 295f153ce47c000debf5f4b92e28cd9442624200 [file] [log] [blame]
Stephane Barbariea188d942018-10-16 16:43:04 -04001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Stephane Barbariedc5022d2018-11-19 15:21:44 -050016
Stephane Barbariea188d942018-10-16 16:43:04 -040017package model
18
19import (
20 "github.com/opencord/voltha-go/common/log"
Stephane Barbariea188d942018-10-16 16:43:04 -040021 "sync"
22 "time"
23)
24
Stephane Barbariedc5022d2018-11-19 15:21:44 -050025type singletonProxyAccessControl struct {
26 sync.RWMutex
Stephane Barbarie933b09b2019-01-09 11:12:09 -050027 cache sync.Map
28 reservedCount int
Stephane Barbariea188d942018-10-16 16:43:04 -040029}
30
Stephane Barbariedc5022d2018-11-19 15:21:44 -050031var instanceProxyAccessControl *singletonProxyAccessControl
32var onceProxyAccessControl sync.Once
Stephane Barbariea188d942018-10-16 16:43:04 -040033
Stephane Barbariedc5022d2018-11-19 15:21:44 -050034// PAC provides access to the proxy access control singleton instance
35func PAC() *singletonProxyAccessControl {
36 onceProxyAccessControl.Do(func() {
Stephane Barbarie933b09b2019-01-09 11:12:09 -050037 instanceProxyAccessControl = &singletonProxyAccessControl{}
Stephane Barbariea188d942018-10-16 16:43:04 -040038 })
Stephane Barbariedc5022d2018-11-19 15:21:44 -050039 return instanceProxyAccessControl
Stephane Barbariea188d942018-10-16 16:43:04 -040040}
41
Stephane Barbariedc5022d2018-11-19 15:21:44 -050042// ReservePath will apply access control for a specific path within the model
Stephane Barbarie933b09b2019-01-09 11:12:09 -050043func (singleton *singletonProxyAccessControl) ReservePath(path string, proxy *Proxy, pathLock string) *proxyAccessControl {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050044 singleton.Lock()
45 defer singleton.Unlock()
Stephane Barbarie933b09b2019-01-09 11:12:09 -050046 singleton.reservedCount++
47 if pac, exists := singleton.cache.Load(pathLock); !exists {
48 log.Debugf("Creating new PAC entry for path:%s pathLock:%s", path, pathLock)
49 newPac := NewProxyAccessControl(proxy, pathLock)
50 singleton.cache.Store(pathLock,newPac)
51 return newPac
Stephane Barbariedc5022d2018-11-19 15:21:44 -050052 } else {
Stephane Barbarie933b09b2019-01-09 11:12:09 -050053 log.Debugf("Re-using existing PAC entry for path:%s pathLock:%s", path, pathLock)
54 return pac.(*proxyAccessControl)
Stephane Barbariedc5022d2018-11-19 15:21:44 -050055 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -050056}
57
58// ReleasePath will remove access control for a specific path within the model
59func (singleton *singletonProxyAccessControl) ReleasePath(pathLock string) {
60 singleton.Lock()
61 defer singleton.Unlock()
Stephane Barbarie933b09b2019-01-09 11:12:09 -050062
63 singleton.reservedCount--
64
65 if singleton.reservedCount == 0 {
66 singleton.cache.Delete(pathLock)
67 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -050068}
69
70// ProxyAccessControl is the abstraction interface to the base proxyAccessControl structure
Stephane Barbariea188d942018-10-16 16:43:04 -040071type ProxyAccessControl interface {
72 Get(path string, depth int, deep bool, txid string, control bool) interface{}
73 Update(path string, data interface{}, strict bool, txid string, control bool) interface{}
74 Add(path string, data interface{}, txid string, control bool) interface{}
75 Remove(path string, txid string, control bool) interface{}
Stephane Barbariedc5022d2018-11-19 15:21:44 -050076 SetProxy(proxy *Proxy)
Stephane Barbariea188d942018-10-16 16:43:04 -040077}
78
Stephane Barbariedc5022d2018-11-19 15:21:44 -050079// proxyAccessControl holds details of the path and proxy that requires access control
Stephane Barbariea188d942018-10-16 16:43:04 -040080type proxyAccessControl struct {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050081 sync.RWMutex
Stephane Barbariea188d942018-10-16 16:43:04 -040082 Proxy *Proxy
83 PathLock chan struct{}
84 Path string
85
86 start time.Time
87 stop time.Time
88}
89
Stephane Barbariedc5022d2018-11-19 15:21:44 -050090// NewProxyAccessControl creates a new instance of an access control structure
Stephane Barbarie933b09b2019-01-09 11:12:09 -050091func NewProxyAccessControl(proxy *Proxy, path string) *proxyAccessControl {
Stephane Barbariea188d942018-10-16 16:43:04 -040092 return &proxyAccessControl{
93 Proxy: proxy,
94 Path: path,
95 PathLock: make(chan struct{}, 1),
96 }
97}
98
Stephane Barbariedc5022d2018-11-19 15:21:44 -050099// lock will prevent access to a model path
Stephane Barbariea188d942018-10-16 16:43:04 -0400100func (pac *proxyAccessControl) lock() {
Stephane Barbariea188d942018-10-16 16:43:04 -0400101 pac.PathLock <- struct{}{}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500102 pac.setStart(time.Now())
Stephane Barbariea188d942018-10-16 16:43:04 -0400103}
104
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500105// unlock will release control of a model path
106func (pac *proxyAccessControl) unlock() {
107 <-pac.PathLock
108 pac.setStop(time.Now())
109 GetProfiling().AddToInMemoryLockTime(pac.getStop().Sub(pac.getStart()).Seconds())
110}
111
112// getStart is used for profiling purposes and returns the time at which access control was applied
113func (pac *proxyAccessControl) getStart() time.Time {
114 pac.Lock()
115 defer pac.Unlock()
116 return pac.start
117}
118
119// getStart is used for profiling purposes and returns the time at which access control was removed
120func (pac *proxyAccessControl) getStop() time.Time {
121 pac.Lock()
122 defer pac.Unlock()
123 return pac.stop
124}
125
126// getPath returns the access controlled path
127func (pac *proxyAccessControl) getPath() string {
128 pac.Lock()
129 defer pac.Unlock()
130 return pac.Path
131}
132
133// getProxy returns the proxy used to reach a specific location in the data model
134func (pac *proxyAccessControl) getProxy() *Proxy {
135 pac.Lock()
136 defer pac.Unlock()
137 return pac.Proxy
138}
139
140// setStart is for profiling purposes and applies a start time value at which access control was started
141func (pac *proxyAccessControl) setStart(time time.Time) {
142 pac.Lock()
143 defer pac.Unlock()
144 pac.start = time
145}
146
147// setStop is for profiling purposes and applies a stop time value at which access control was stopped
148func (pac *proxyAccessControl) setStop(time time.Time) {
149 pac.Lock()
150 defer pac.Unlock()
151 pac.stop = time
152}
153
154// SetProxy is used to changed the proxy object of an access controlled path
155func (pac *proxyAccessControl) SetProxy(proxy *Proxy) {
156 pac.Lock()
157 defer pac.Unlock()
158 pac.Proxy = proxy
159}
160
Stephane Barbarieaa467942019-02-06 14:09:44 -0500161// List retrieves data linked to a data model path
162func (pac *proxyAccessControl) List(path string, depth int, deep bool, txid string, control bool) interface{} {
163 if control {
164 pac.lock()
Stephane Barbarie260a5632019-02-26 16:12:49 -0500165 log.Debugw("locked-access--list", log.Fields{"path":pac.Proxy.getFullPath()})
Stephane Barbarieaa467942019-02-06 14:09:44 -0500166 defer pac.unlock()
Stephane Barbarie260a5632019-02-26 16:12:49 -0500167 defer log.Debugw("unlocked-access--list", log.Fields{"path":pac.Proxy.getFullPath()})
Stephane Barbarieaa467942019-02-06 14:09:44 -0500168 }
169
170 // FIXME: Forcing depth to 0 for now due to problems deep copying the data structure
171 // The data traversal through reflection currently corrupts the content
172
173 return pac.getProxy().GetRoot().List(path, "", depth, deep, txid)
174}
175
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500176// Get retrieves data linked to a data model path
Stephane Barbariea188d942018-10-16 16:43:04 -0400177func (pac *proxyAccessControl) Get(path string, depth int, deep bool, txid string, control bool) interface{} {
178 if control {
179 pac.lock()
Stephane Barbarie260a5632019-02-26 16:12:49 -0500180 log.Debugw("locked-access--get", log.Fields{"path":pac.Proxy.getFullPath()})
Stephane Barbariea188d942018-10-16 16:43:04 -0400181 defer pac.unlock()
Stephane Barbarie260a5632019-02-26 16:12:49 -0500182 defer log.Debugw("unlocked-access--get", log.Fields{"path":pac.Proxy.getFullPath()})
Stephane Barbariea188d942018-10-16 16:43:04 -0400183 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500184
185 // FIXME: Forcing depth to 0 for now due to problems deep copying the data structure
186 // The data traversal through reflection currently corrupts the content
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500187 return pac.getProxy().GetRoot().Get(path, "", 0, deep, txid)
Stephane Barbariea188d942018-10-16 16:43:04 -0400188}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500189
190// Update changes the content of the data model at the specified location with the provided data
Stephane Barbariea188d942018-10-16 16:43:04 -0400191func (pac *proxyAccessControl) Update(path string, data interface{}, strict bool, txid string, control bool) interface{} {
192 if control {
193 pac.lock()
Stephane Barbarie260a5632019-02-26 16:12:49 -0500194 log.Debugw("locked-access--update", log.Fields{"path":pac.Proxy.getFullPath()})
Stephane Barbariea188d942018-10-16 16:43:04 -0400195 defer pac.unlock()
Stephane Barbarie260a5632019-02-26 16:12:49 -0500196 defer log.Debugw("unlocked-access--update", log.Fields{"path":pac.Proxy.getFullPath()})
Stephane Barbariea188d942018-10-16 16:43:04 -0400197 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500198 result := pac.getProxy().GetRoot().Update(path, data, strict, txid, nil)
199
200 if result != nil {
201 return result.GetData()
202 }
203 return nil
Stephane Barbariea188d942018-10-16 16:43:04 -0400204}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500205
206// Add creates a new data model entry at the specified location with the provided data
Stephane Barbariea188d942018-10-16 16:43:04 -0400207func (pac *proxyAccessControl) Add(path string, data interface{}, txid string, control bool) interface{} {
208 if control {
209 pac.lock()
Stephane Barbarie260a5632019-02-26 16:12:49 -0500210 log.Debugw("locked-access--add", log.Fields{"path":pac.Proxy.getFullPath()})
Stephane Barbariea188d942018-10-16 16:43:04 -0400211 defer pac.unlock()
Stephane Barbarie260a5632019-02-26 16:12:49 -0500212 defer log.Debugw("unlocked-access--add", log.Fields{"path":pac.Proxy.getFullPath()})
Stephane Barbariea188d942018-10-16 16:43:04 -0400213 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500214 result := pac.getProxy().GetRoot().Add(path, data, txid, nil)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500215
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500216 if result != nil {
217 return result.GetData()
218 }
219 return nil
Stephane Barbariea188d942018-10-16 16:43:04 -0400220}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500221
222// Remove discards information linked to the data model path
Stephane Barbariea188d942018-10-16 16:43:04 -0400223func (pac *proxyAccessControl) Remove(path string, txid string, control bool) interface{} {
224 if control {
225 pac.lock()
Stephane Barbarie260a5632019-02-26 16:12:49 -0500226 log.Debugw("locked-access--remove", log.Fields{"path":pac.Proxy.getFullPath()})
Stephane Barbariea188d942018-10-16 16:43:04 -0400227 defer pac.unlock()
Stephane Barbarie260a5632019-02-26 16:12:49 -0500228 defer log.Debugw("unlocked-access--remove", log.Fields{"path":pac.Proxy.getFullPath()})
Stephane Barbariea188d942018-10-16 16:43:04 -0400229 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500230 return pac.getProxy().GetRoot().Remove(path, txid, nil)
Stephane Barbariea188d942018-10-16 16:43:04 -0400231}