blob: 990a61ca14ef6fac837d98c049e0bd21f047d496 [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
Stephane Barbarie933b09b2019-01-09 11:12:09 -050028 cache sync.Map
29 reservedCount int
Stephane Barbariea188d942018-10-16 16:43:04 -040030}
31
Stephane Barbariedc5022d2018-11-19 15:21:44 -050032var instanceProxyAccessControl *singletonProxyAccessControl
33var onceProxyAccessControl sync.Once
Stephane Barbariea188d942018-10-16 16:43:04 -040034
Stephane Barbariedc5022d2018-11-19 15:21:44 -050035// PAC provides access to the proxy access control singleton instance
36func PAC() *singletonProxyAccessControl {
37 onceProxyAccessControl.Do(func() {
Stephane Barbarie933b09b2019-01-09 11:12:09 -050038 instanceProxyAccessControl = &singletonProxyAccessControl{}
Stephane Barbariea188d942018-10-16 16:43:04 -040039 })
Stephane Barbariedc5022d2018-11-19 15:21:44 -050040 return instanceProxyAccessControl
Stephane Barbariea188d942018-10-16 16:43:04 -040041}
42
Stephane Barbariedc5022d2018-11-19 15:21:44 -050043// ReservePath will apply access control for a specific path within the model
Stephane Barbarie933b09b2019-01-09 11:12:09 -050044func (singleton *singletonProxyAccessControl) ReservePath(path string, proxy *Proxy, pathLock string) *proxyAccessControl {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050045 singleton.Lock()
46 defer singleton.Unlock()
Stephane Barbarie933b09b2019-01-09 11:12:09 -050047 singleton.reservedCount++
48 if pac, exists := singleton.cache.Load(pathLock); !exists {
49 log.Debugf("Creating new PAC entry for path:%s pathLock:%s", path, pathLock)
50 newPac := NewProxyAccessControl(proxy, pathLock)
51 singleton.cache.Store(pathLock,newPac)
52 return newPac
Stephane Barbariedc5022d2018-11-19 15:21:44 -050053 } else {
Stephane Barbarie933b09b2019-01-09 11:12:09 -050054 log.Debugf("Re-using existing PAC entry for path:%s pathLock:%s", path, pathLock)
55 return pac.(*proxyAccessControl)
Stephane Barbariedc5022d2018-11-19 15:21:44 -050056 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -050057}
58
59// ReleasePath will remove access control for a specific path within the model
60func (singleton *singletonProxyAccessControl) ReleasePath(pathLock string) {
61 singleton.Lock()
62 defer singleton.Unlock()
Stephane Barbarie933b09b2019-01-09 11:12:09 -050063
64 singleton.reservedCount--
65
66 if singleton.reservedCount == 0 {
67 singleton.cache.Delete(pathLock)
68 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -050069}
70
71// ProxyAccessControl is the abstraction interface to the base proxyAccessControl structure
Stephane Barbariea188d942018-10-16 16:43:04 -040072type ProxyAccessControl interface {
73 Get(path string, depth int, deep bool, txid string, control bool) interface{}
74 Update(path string, data interface{}, strict bool, txid string, control bool) interface{}
75 Add(path string, data interface{}, txid string, control bool) interface{}
76 Remove(path string, txid string, control bool) interface{}
Stephane Barbariedc5022d2018-11-19 15:21:44 -050077 SetProxy(proxy *Proxy)
Stephane Barbariea188d942018-10-16 16:43:04 -040078}
79
Stephane Barbariedc5022d2018-11-19 15:21:44 -050080// proxyAccessControl holds details of the path and proxy that requires access control
Stephane Barbariea188d942018-10-16 16:43:04 -040081type proxyAccessControl struct {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050082 sync.RWMutex
Stephane Barbariea188d942018-10-16 16:43:04 -040083 Proxy *Proxy
84 PathLock chan struct{}
85 Path string
86
87 start time.Time
88 stop time.Time
89}
90
Stephane Barbariedc5022d2018-11-19 15:21:44 -050091// NewProxyAccessControl creates a new instance of an access control structure
Stephane Barbarie933b09b2019-01-09 11:12:09 -050092func NewProxyAccessControl(proxy *Proxy, path string) *proxyAccessControl {
Stephane Barbariea188d942018-10-16 16:43:04 -040093 return &proxyAccessControl{
94 Proxy: proxy,
95 Path: path,
96 PathLock: make(chan struct{}, 1),
97 }
98}
99
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500100// lock will prevent access to a model path
Stephane Barbariea188d942018-10-16 16:43:04 -0400101func (pac *proxyAccessControl) lock() {
Stephane Barbariea188d942018-10-16 16:43:04 -0400102 pac.PathLock <- struct{}{}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500103 pac.setStart(time.Now())
Stephane Barbariea188d942018-10-16 16:43:04 -0400104}
105
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500106// unlock will release control of a model path
107func (pac *proxyAccessControl) unlock() {
108 <-pac.PathLock
109 pac.setStop(time.Now())
110 GetProfiling().AddToInMemoryLockTime(pac.getStop().Sub(pac.getStart()).Seconds())
111}
112
113// getStart is used for profiling purposes and returns the time at which access control was applied
114func (pac *proxyAccessControl) getStart() time.Time {
115 pac.Lock()
116 defer pac.Unlock()
117 return pac.start
118}
119
120// getStart is used for profiling purposes and returns the time at which access control was removed
121func (pac *proxyAccessControl) getStop() time.Time {
122 pac.Lock()
123 defer pac.Unlock()
124 return pac.stop
125}
126
127// getPath returns the access controlled path
128func (pac *proxyAccessControl) getPath() string {
129 pac.Lock()
130 defer pac.Unlock()
131 return pac.Path
132}
133
134// getProxy returns the proxy used to reach a specific location in the data model
135func (pac *proxyAccessControl) getProxy() *Proxy {
136 pac.Lock()
137 defer pac.Unlock()
138 return pac.Proxy
139}
140
141// setStart is for profiling purposes and applies a start time value at which access control was started
142func (pac *proxyAccessControl) setStart(time time.Time) {
143 pac.Lock()
144 defer pac.Unlock()
145 pac.start = time
146}
147
148// setStop is for profiling purposes and applies a stop time value at which access control was stopped
149func (pac *proxyAccessControl) setStop(time time.Time) {
150 pac.Lock()
151 defer pac.Unlock()
152 pac.stop = time
153}
154
155// SetProxy is used to changed the proxy object of an access controlled path
156func (pac *proxyAccessControl) SetProxy(proxy *Proxy) {
157 pac.Lock()
158 defer pac.Unlock()
159 pac.Proxy = proxy
160}
161
162// Get retrieves data linked to a data model path
Stephane Barbariea188d942018-10-16 16:43:04 -0400163func (pac *proxyAccessControl) Get(path string, depth int, deep bool, txid string, control bool) interface{} {
164 if control {
165 pac.lock()
166 defer pac.unlock()
167 log.Debugf("controlling get, stack = %s", string(debug.Stack()))
168 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500169
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
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500173 return pac.getProxy().GetRoot().Get(path, "", depth, deep, txid)
Stephane Barbariea188d942018-10-16 16:43:04 -0400174}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500175
176// Update changes the content of the data model at the specified location with the provided data
Stephane Barbariea188d942018-10-16 16:43:04 -0400177func (pac *proxyAccessControl) Update(path string, data interface{}, strict bool, txid string, control bool) interface{} {
178 if control {
179 pac.lock()
180 defer pac.unlock()
181 log.Debugf("controlling update, stack = %s", string(debug.Stack()))
182 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500183 result := pac.getProxy().GetRoot().Update(path, data, strict, txid, nil)
184
185 if result != nil {
186 return result.GetData()
187 }
188 return nil
Stephane Barbariea188d942018-10-16 16:43:04 -0400189}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500190
191// Add creates a new data model entry at the specified location with the provided data
Stephane Barbariea188d942018-10-16 16:43:04 -0400192func (pac *proxyAccessControl) Add(path string, data interface{}, txid string, control bool) interface{} {
193 if control {
194 pac.lock()
195 defer pac.unlock()
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500196 log.Debugf("controlling add %s, stack = %s", pac.Path, string(debug.Stack()))
Stephane Barbariea188d942018-10-16 16:43:04 -0400197 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500198 result := pac.getProxy().GetRoot().Add(path, data, txid, nil)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500199
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500200 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// Remove discards information linked to the data model path
Stephane Barbariea188d942018-10-16 16:43:04 -0400207func (pac *proxyAccessControl) Remove(path string, txid string, control bool) interface{} {
208 if control {
209 pac.lock()
210 defer pac.unlock()
211 log.Debugf("controlling remove, stack = %s", string(debug.Stack()))
212 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500213 return pac.getProxy().GetRoot().Remove(path, txid, nil)
Stephane Barbariea188d942018-10-16 16:43:04 -0400214}