blob: f6169b652e0e1c0900d1c65214b1dea52f5ae9e7 [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"
21 "runtime/debug"
22 "sync"
23 "time"
24)
25
Stephane Barbariedc5022d2018-11-19 15:21:44 -050026type singletonProxyAccessControl struct {
27 sync.RWMutex
28 cache map[string]ProxyAccessControl
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() {
37 instanceProxyAccessControl = &singletonProxyAccessControl{cache: make(map[string]ProxyAccessControl)}
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
43func (singleton *singletonProxyAccessControl) ReservePath(path string, proxy *Proxy, pathLock string) ProxyAccessControl {
44 singleton.Lock()
45 defer singleton.Unlock()
46 var pac ProxyAccessControl
47 var exists bool
48 if pac, exists = singleton.cache[path]; !exists {
49 pac = NewProxyAccessControl(proxy, pathLock)
50 singleton.cache[path] = pac
51 }
52
53 if exists {
54 log.Debugf("PAC exists for path: %s... re-using", path)
55 } else {
56 log.Debugf("PAC does not exists for path: %s... creating", path)
57 }
58 return pac
59}
60
61// ReleasePath will remove access control for a specific path within the model
62func (singleton *singletonProxyAccessControl) ReleasePath(pathLock string) {
63 singleton.Lock()
64 defer singleton.Unlock()
65 delete(singleton.cache, pathLock)
66}
67
68// ProxyAccessControl is the abstraction interface to the base proxyAccessControl structure
Stephane Barbariea188d942018-10-16 16:43:04 -040069type ProxyAccessControl interface {
70 Get(path string, depth int, deep bool, txid string, control bool) interface{}
71 Update(path string, data interface{}, strict bool, txid string, control bool) interface{}
72 Add(path string, data interface{}, txid string, control bool) interface{}
73 Remove(path string, txid string, control bool) interface{}
Stephane Barbariedc5022d2018-11-19 15:21:44 -050074 SetProxy(proxy *Proxy)
Stephane Barbariea188d942018-10-16 16:43:04 -040075}
76
Stephane Barbariedc5022d2018-11-19 15:21:44 -050077// proxyAccessControl holds details of the path and proxy that requires access control
Stephane Barbariea188d942018-10-16 16:43:04 -040078type proxyAccessControl struct {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050079 sync.RWMutex
Stephane Barbariea188d942018-10-16 16:43:04 -040080 Proxy *Proxy
81 PathLock chan struct{}
82 Path string
83
84 start time.Time
85 stop time.Time
86}
87
Stephane Barbariedc5022d2018-11-19 15:21:44 -050088// NewProxyAccessControl creates a new instance of an access control structure
Stephane Barbariea188d942018-10-16 16:43:04 -040089func NewProxyAccessControl(proxy *Proxy, path string) ProxyAccessControl {
90 return &proxyAccessControl{
91 Proxy: proxy,
92 Path: path,
93 PathLock: make(chan struct{}, 1),
94 }
95}
96
Stephane Barbariedc5022d2018-11-19 15:21:44 -050097// lock will prevent access to a model path
Stephane Barbariea188d942018-10-16 16:43:04 -040098func (pac *proxyAccessControl) lock() {
Stephane Barbariea188d942018-10-16 16:43:04 -040099 pac.PathLock <- struct{}{}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500100 pac.setStart(time.Now())
Stephane Barbariea188d942018-10-16 16:43:04 -0400101}
102
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500103// unlock will release control of a model path
104func (pac *proxyAccessControl) unlock() {
105 <-pac.PathLock
106 pac.setStop(time.Now())
107 GetProfiling().AddToInMemoryLockTime(pac.getStop().Sub(pac.getStart()).Seconds())
108}
109
110// getStart is used for profiling purposes and returns the time at which access control was applied
111func (pac *proxyAccessControl) getStart() time.Time {
112 pac.Lock()
113 defer pac.Unlock()
114 return pac.start
115}
116
117// getStart is used for profiling purposes and returns the time at which access control was removed
118func (pac *proxyAccessControl) getStop() time.Time {
119 pac.Lock()
120 defer pac.Unlock()
121 return pac.stop
122}
123
124// getPath returns the access controlled path
125func (pac *proxyAccessControl) getPath() string {
126 pac.Lock()
127 defer pac.Unlock()
128 return pac.Path
129}
130
131// getProxy returns the proxy used to reach a specific location in the data model
132func (pac *proxyAccessControl) getProxy() *Proxy {
133 pac.Lock()
134 defer pac.Unlock()
135 return pac.Proxy
136}
137
138// setStart is for profiling purposes and applies a start time value at which access control was started
139func (pac *proxyAccessControl) setStart(time time.Time) {
140 pac.Lock()
141 defer pac.Unlock()
142 pac.start = time
143}
144
145// setStop is for profiling purposes and applies a stop time value at which access control was stopped
146func (pac *proxyAccessControl) setStop(time time.Time) {
147 pac.Lock()
148 defer pac.Unlock()
149 pac.stop = time
150}
151
152// SetProxy is used to changed the proxy object of an access controlled path
153func (pac *proxyAccessControl) SetProxy(proxy *Proxy) {
154 pac.Lock()
155 defer pac.Unlock()
156 pac.Proxy = proxy
157}
158
159// Get retrieves data linked to a data model path
Stephane Barbariea188d942018-10-16 16:43:04 -0400160func (pac *proxyAccessControl) Get(path string, depth int, deep bool, txid string, control bool) interface{} {
161 if control {
162 pac.lock()
163 defer pac.unlock()
164 log.Debugf("controlling get, stack = %s", string(debug.Stack()))
165 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500166
167 // FIXME: Forcing depth to 0 for now due to problems deep copying the data structure
168 // The data traversal through reflection currently corrupts the content
169
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500170 return pac.getProxy().GetRoot().Get(path, "", depth, deep, txid)
Stephane Barbariea188d942018-10-16 16:43:04 -0400171}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500172
173// Update changes the content of the data model at the specified location with the provided data
Stephane Barbariea188d942018-10-16 16:43:04 -0400174func (pac *proxyAccessControl) Update(path string, data interface{}, strict bool, txid string, control bool) interface{} {
175 if control {
176 pac.lock()
177 defer pac.unlock()
178 log.Debugf("controlling update, stack = %s", string(debug.Stack()))
179 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500180 result := pac.getProxy().GetRoot().Update(path, data, strict, txid, nil)
181
182 if result != nil {
183 return result.GetData()
184 }
185 return nil
Stephane Barbariea188d942018-10-16 16:43:04 -0400186}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500187
188// Add creates a new data model entry at the specified location with the provided data
Stephane Barbariea188d942018-10-16 16:43:04 -0400189func (pac *proxyAccessControl) Add(path string, data interface{}, txid string, control bool) interface{} {
190 if control {
191 pac.lock()
192 defer pac.unlock()
193 log.Debugf("controlling add, stack = %s", string(debug.Stack()))
194 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500195 result := pac.getProxy().GetRoot().Add(path, data, txid, nil)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500196
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500197 if result != nil {
198 return result.GetData()
199 }
200 return nil
Stephane Barbariea188d942018-10-16 16:43:04 -0400201}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500202
203// Remove discards information linked to the data model path
Stephane Barbariea188d942018-10-16 16:43:04 -0400204func (pac *proxyAccessControl) Remove(path string, txid string, control bool) interface{} {
205 if control {
206 pac.lock()
207 defer pac.unlock()
208 log.Debugf("controlling remove, stack = %s", string(debug.Stack()))
209 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500210 return pac.getProxy().GetRoot().Remove(path, txid, nil)
Stephane Barbariea188d942018-10-16 16:43:04 -0400211}