blob: 215f60f72d62f5641686dfda6ab2d0315ff3f417 [file] [log] [blame]
khenaidoobf6e7bb2018-08-14 22:27:29 -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 */
khenaidoob9203542018-09-17 22:56:37 -040016package core
khenaidoobf6e7bb2018-08-14 22:27:29 -040017
18import (
19 "context"
20 "errors"
21 "github.com/golang/protobuf/ptypes/empty"
22 da "github.com/opencord/voltha-go/common/core/northbound/grpc"
23 "github.com/opencord/voltha-go/common/log"
24 "github.com/opencord/voltha-go/protos/common"
25 "github.com/opencord/voltha-go/protos/openflow_13"
26 "github.com/opencord/voltha-go/protos/voltha"
khenaidoob9203542018-09-17 22:56:37 -040027 "google.golang.org/grpc/codes"
khenaidoobf6e7bb2018-08-14 22:27:29 -040028 "google.golang.org/grpc/metadata"
khenaidoob9203542018-09-17 22:56:37 -040029 "google.golang.org/grpc/status"
khenaidoobf6e7bb2018-08-14 22:27:29 -040030)
31
Richard Jankowskid42826e2018-11-02 16:06:37 -040032const MAX_RESPONSE_TIME = 500 // milliseconds
33
khenaidoobf6e7bb2018-08-14 22:27:29 -040034type APIHandler struct {
khenaidoob9203542018-09-17 22:56:37 -040035 deviceMgr *DeviceManager
36 logicalDeviceMgr *LogicalDeviceManager
khenaidoobf6e7bb2018-08-14 22:27:29 -040037 da.DefaultAPIHandler
38}
39
khenaidoo9a468962018-09-19 15:33:13 -040040func NewAPIHandler(deviceMgr *DeviceManager, lDeviceMgr *LogicalDeviceManager) *APIHandler {
khenaidoob9203542018-09-17 22:56:37 -040041 handler := &APIHandler{deviceMgr: deviceMgr,
khenaidoo9a468962018-09-19 15:33:13 -040042 logicalDeviceMgr: lDeviceMgr}
khenaidoobf6e7bb2018-08-14 22:27:29 -040043 return handler
44}
khenaidoo4d4802d2018-10-04 21:59:49 -040045
46// isTestMode is a helper function to determine a function is invoked for testing only
khenaidoobf6e7bb2018-08-14 22:27:29 -040047func isTestMode(ctx context.Context) bool {
48 md, _ := metadata.FromIncomingContext(ctx)
49 _, exist := md[common.TestModeKeys_api_test.String()]
50 return exist
51}
52
Richard Jankowskid42826e2018-11-02 16:06:37 -040053// This function attempts to extract the serial number from the request metadata
54// and create a KV transaction for that serial number for the current core.
55func (handler *APIHandler) createKvTransaction(ctx context.Context) (*KVTransaction, error) {
56 var (
57 err error
58 ok bool
59 md metadata.MD
60 serNum []string
61 )
62 if md, ok = metadata.FromIncomingContext(ctx); !ok {
63 err = errors.New("metadata-not-found")
64 } else if serNum, ok = md["voltha_serial_number"]; !ok {
65 err = errors.New("serial-number-not-found")
66 }
67 if !ok {
68 log.Error(err)
69 return nil, err
70 }
71 // Create KV transaction
72 txn := NewKVTransaction(serNum[0])
73 return txn, nil
74}
75
khenaidoo4d4802d2018-10-04 21:59:49 -040076// waitForNilResponseOnSuccess is a helper function to wait for a response on channel ch where an nil
77// response is expected in a successful scenario
78func waitForNilResponseOnSuccess(ctx context.Context, ch chan interface{}) (*empty.Empty, error) {
79 select {
80 case res := <-ch:
81 if res == nil {
82 return new(empty.Empty), nil
83 } else if err, ok := res.(error); ok {
84 return new(empty.Empty), err
85 } else {
86 log.Warnw("unexpected-return-type", log.Fields{"result": res})
87 err = status.Errorf(codes.Internal, "%s", res)
88 return new(empty.Empty), err
89 }
90 case <-ctx.Done():
91 log.Debug("client-timeout")
92 return nil, ctx.Err()
93 }
94}
95
khenaidoobf6e7bb2018-08-14 22:27:29 -040096func (handler *APIHandler) UpdateLogLevel(ctx context.Context, logging *voltha.Logging) (*empty.Empty, error) {
97 log.Debugw("UpdateLogLevel-request", log.Fields{"newloglevel": logging.Level, "intval": int(logging.Level)})
khenaidoo92e62c52018-10-03 14:02:54 -040098 out := new(empty.Empty)
99 log.SetPackageLogLevel(logging.PackageName, int(logging.Level))
100 return out, nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400101}
102
103func (handler *APIHandler) EnableLogicalDevicePort(ctx context.Context, id *voltha.LogicalPortId) (*empty.Empty, error) {
104 log.Debugw("EnableLogicalDevicePort-request", log.Fields{"id": id, "test": common.TestModeKeys_api_test.String()})
105 if isTestMode(ctx) {
106 out := new(empty.Empty)
107 return out, nil
108 }
khenaidoo4d4802d2018-10-04 21:59:49 -0400109 ch := make(chan interface{})
110 defer close(ch)
khenaidoo19d7b632018-10-30 10:49:50 -0400111 go handler.logicalDeviceMgr.enableLogicalPort(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400112 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400113}
114
115func (handler *APIHandler) DisableLogicalDevicePort(ctx context.Context, id *voltha.LogicalPortId) (*empty.Empty, error) {
116 log.Debugw("DisableLogicalDevicePort-request", log.Fields{"id": id, "test": common.TestModeKeys_api_test.String()})
117 if isTestMode(ctx) {
118 out := new(empty.Empty)
119 return out, nil
120 }
khenaidoo19d7b632018-10-30 10:49:50 -0400121 ch := make(chan interface{})
122 defer close(ch)
123 go handler.logicalDeviceMgr.disableLogicalPort(ctx, id, ch)
124 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400125}
126
127func (handler *APIHandler) UpdateLogicalDeviceFlowTable(ctx context.Context, flow *openflow_13.FlowTableUpdate) (*empty.Empty, error) {
128 log.Debugw("UpdateLogicalDeviceFlowTable-request", log.Fields{"flow": flow, "test": common.TestModeKeys_api_test.String()})
129 if isTestMode(ctx) {
130 out := new(empty.Empty)
131 return out, nil
132 }
khenaidoo19d7b632018-10-30 10:49:50 -0400133 ch := make(chan interface{})
134 defer close(ch)
135 go handler.logicalDeviceMgr.updateFlowTable(ctx, flow.Id, flow.FlowMod, ch)
136 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400137}
138
139func (handler *APIHandler) UpdateLogicalDeviceFlowGroupTable(ctx context.Context, flow *openflow_13.FlowGroupTableUpdate) (*empty.Empty, error) {
140 log.Debugw("UpdateLogicalDeviceFlowGroupTable-request", log.Fields{"flow": flow, "test": common.TestModeKeys_api_test.String()})
141 if isTestMode(ctx) {
142 out := new(empty.Empty)
143 return out, nil
144 }
khenaidoo19d7b632018-10-30 10:49:50 -0400145 ch := make(chan interface{})
146 defer close(ch)
147 go handler.logicalDeviceMgr.updateGroupTable(ctx, flow.Id, flow.GroupMod, ch)
148 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400149}
150
khenaidoob9203542018-09-17 22:56:37 -0400151// GetDevice must be implemented in the read-only containers - should it also be implemented here?
152func (handler *APIHandler) GetDevice(ctx context.Context, id *voltha.ID) (*voltha.Device, error) {
153 log.Debugw("GetDevice-request", log.Fields{"id": id})
khenaidoo19d7b632018-10-30 10:49:50 -0400154 return handler.deviceMgr.GetDevice(id.Id)
khenaidoob9203542018-09-17 22:56:37 -0400155}
156
157// GetDevice must be implemented in the read-only containers - should it also be implemented here?
158func (handler *APIHandler) ListDevices(ctx context.Context, empty *empty.Empty) (*voltha.Devices, error) {
159 log.Debug("ListDevices")
160 return handler.deviceMgr.ListDevices()
161}
162
163// GetLogicalDevice must be implemented in the read-only containers - should it also be implemented here?
164func (handler *APIHandler) GetLogicalDevice(ctx context.Context, id *voltha.ID) (*voltha.LogicalDevice, error) {
165 log.Debugw("GetLogicalDevice-request", log.Fields{"id": id})
166 return handler.logicalDeviceMgr.getLogicalDevice(id.Id)
167}
168
169// ListLogicalDevices must be implemented in the read-only containers - should it also be implemented here?
170func (handler *APIHandler) ListLogicalDevices(ctx context.Context, empty *empty.Empty) (*voltha.LogicalDevices, error) {
171 log.Debug("ListLogicalDevices")
172 return handler.logicalDeviceMgr.listLogicalDevices()
173}
174
khenaidoo19d7b632018-10-30 10:49:50 -0400175// ListLogicalDevicePorts must be implemented in the read-only containers - should it also be implemented here?
176func (handler *APIHandler) ListLogicalDevicePorts(ctx context.Context, id *voltha.ID) (*voltha.LogicalPorts, error) {
177 log.Debugw("ListLogicalDevicePorts", log.Fields{"logicaldeviceid": id})
178 return handler.logicalDeviceMgr.ListLogicalDevicePorts(ctx, id.Id)
179}
180
khenaidoo4d4802d2018-10-04 21:59:49 -0400181// CreateDevice creates a new parent device in the data model
khenaidoobf6e7bb2018-08-14 22:27:29 -0400182func (handler *APIHandler) CreateDevice(ctx context.Context, device *voltha.Device) (*voltha.Device, error) {
khenaidoob9203542018-09-17 22:56:37 -0400183 log.Debugw("createdevice", log.Fields{"device": *device})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400184 if isTestMode(ctx) {
185 return &voltha.Device{Id: device.Id}, nil
186 }
Richard Jankowskid42826e2018-11-02 16:06:37 -0400187
188 txn, err := handler.createKvTransaction(ctx)
189 if txn == nil {
190 return &voltha.Device{}, err
191 } else if txn.Acquired(MAX_RESPONSE_TIME) {
192 defer txn.Close() // Ensure active core signals "done" to standby
193 } else {
194 return &voltha.Device{}, nil
195 }
196
khenaidoob9203542018-09-17 22:56:37 -0400197 ch := make(chan interface{})
198 defer close(ch)
199 go handler.deviceMgr.createDevice(ctx, device, ch)
200 select {
201 case res := <-ch:
khenaidoo92e62c52018-10-03 14:02:54 -0400202 if res != nil {
203 if err, ok := res.(error); ok {
204 return &voltha.Device{}, err
205 }
206 if d, ok := res.(*voltha.Device); ok {
207 return d, nil
208 }
khenaidoob9203542018-09-17 22:56:37 -0400209 }
khenaidoo92e62c52018-10-03 14:02:54 -0400210 log.Warnw("create-device-unexpected-return-type", log.Fields{"result": res})
211 err := status.Errorf(codes.Internal, "%s", res)
212 return &voltha.Device{}, err
khenaidoob9203542018-09-17 22:56:37 -0400213 case <-ctx.Done():
214 log.Debug("createdevice-client-timeout")
215 return nil, ctx.Err()
216 }
khenaidoobf6e7bb2018-08-14 22:27:29 -0400217}
218
khenaidoo4d4802d2018-10-04 21:59:49 -0400219// EnableDevice activates a device by invoking the adopt_device API on the appropriate adapter
khenaidoobf6e7bb2018-08-14 22:27:29 -0400220func (handler *APIHandler) EnableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
khenaidoob9203542018-09-17 22:56:37 -0400221 log.Debugw("enabledevice", log.Fields{"id": id})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400222 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400223 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400224 }
Richard Jankowskid42826e2018-11-02 16:06:37 -0400225
226 txn, err := handler.createKvTransaction(ctx)
227 if txn == nil {
228 return new(empty.Empty), err
229 } else if txn.Acquired(MAX_RESPONSE_TIME) {
230 defer txn.Close() // Ensure active core signals "done" to standby
231 } else {
232 return new(empty.Empty), nil
233 }
234
khenaidoob9203542018-09-17 22:56:37 -0400235 ch := make(chan interface{})
236 defer close(ch)
237 go handler.deviceMgr.enableDevice(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400238 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400239}
240
khenaidoo4d4802d2018-10-04 21:59:49 -0400241// DisableDevice disables a device along with any child device it may have
khenaidoobf6e7bb2018-08-14 22:27:29 -0400242func (handler *APIHandler) DisableDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
243 log.Debugw("disabledevice-request", log.Fields{"id": id})
244 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400245 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400246 }
khenaidoo92e62c52018-10-03 14:02:54 -0400247 ch := make(chan interface{})
248 defer close(ch)
249 go handler.deviceMgr.disableDevice(ctx, id, ch)
khenaidoo4d4802d2018-10-04 21:59:49 -0400250 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400251}
252
khenaidoo4d4802d2018-10-04 21:59:49 -0400253//RebootDevice invoked the reboot API to the corresponding adapter
khenaidoobf6e7bb2018-08-14 22:27:29 -0400254func (handler *APIHandler) RebootDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400255 log.Debugw("rebootDevice-request", log.Fields{"id": id})
khenaidoobf6e7bb2018-08-14 22:27:29 -0400256 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400257 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400258 }
khenaidoo4d4802d2018-10-04 21:59:49 -0400259 ch := make(chan interface{})
260 defer close(ch)
261 go handler.deviceMgr.rebootDevice(ctx, id, ch)
262 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400263}
264
khenaidoo4d4802d2018-10-04 21:59:49 -0400265// DeleteDevice removes a device from the data model
khenaidoobf6e7bb2018-08-14 22:27:29 -0400266func (handler *APIHandler) DeleteDevice(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
267 log.Debugw("deletedevice-request", log.Fields{"id": id})
268 if isTestMode(ctx) {
khenaidoo4d4802d2018-10-04 21:59:49 -0400269 return new(empty.Empty), nil
khenaidoobf6e7bb2018-08-14 22:27:29 -0400270 }
khenaidoo4d4802d2018-10-04 21:59:49 -0400271 ch := make(chan interface{})
272 defer close(ch)
273 go handler.deviceMgr.deleteDevice(ctx, id, ch)
274 return waitForNilResponseOnSuccess(ctx, ch)
khenaidoobf6e7bb2018-08-14 22:27:29 -0400275}
276
277func (handler *APIHandler) DownloadImage(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
278 log.Debugw("DownloadImage-request", log.Fields{"img": *img})
279 if isTestMode(ctx) {
280 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
281 return resp, nil
282 }
283
284 return nil, errors.New("UnImplemented")
285}
286
287func (handler *APIHandler) CancelImageDownload(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
288 log.Debugw("CancelImageDownload-request", log.Fields{"img": *img})
289 if isTestMode(ctx) {
290 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
291 return resp, nil
292 }
293 return nil, errors.New("UnImplemented")
294}
295
296func (handler *APIHandler) ActivateImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
297 log.Debugw("ActivateImageUpdate-request", log.Fields{"img": *img})
298 if isTestMode(ctx) {
299 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
300 return resp, nil
301 }
302 return nil, errors.New("UnImplemented")
303}
304
305func (handler *APIHandler) RevertImageUpdate(ctx context.Context, img *voltha.ImageDownload) (*common.OperationResp, error) {
306 log.Debugw("RevertImageUpdate-request", log.Fields{"img": *img})
307 if isTestMode(ctx) {
308 resp := &common.OperationResp{Code: common.OperationResp_OPERATION_SUCCESS}
309 return resp, nil
310 }
311 return nil, errors.New("UnImplemented")
312}
313
314func (handler *APIHandler) UpdateDevicePmConfigs(ctx context.Context, configs *voltha.PmConfigs) (*empty.Empty, error) {
315 log.Debugw("UpdateDevicePmConfigs-request", log.Fields{"configs": *configs})
316 if isTestMode(ctx) {
317 out := new(empty.Empty)
318 return out, nil
319 }
320 return nil, errors.New("UnImplemented")
321}
322
323func (handler *APIHandler) CreateAlarmFilter(ctx context.Context, filter *voltha.AlarmFilter) (*voltha.AlarmFilter, error) {
324 log.Debugw("CreateAlarmFilter-request", log.Fields{"filter": *filter})
325 if isTestMode(ctx) {
326 f := &voltha.AlarmFilter{Id: filter.Id}
327 return f, nil
328 }
329 return nil, errors.New("UnImplemented")
330}
331
332func (handler *APIHandler) UpdateAlarmFilter(ctx context.Context, filter *voltha.AlarmFilter) (*voltha.AlarmFilter, error) {
333 log.Debugw("UpdateAlarmFilter-request", log.Fields{"filter": *filter})
334 if isTestMode(ctx) {
335 f := &voltha.AlarmFilter{Id: filter.Id}
336 return f, nil
337 }
338 return nil, errors.New("UnImplemented")
339}
340
341func (handler *APIHandler) DeleteAlarmFilter(ctx context.Context, id *voltha.ID) (*empty.Empty, error) {
342 log.Debugw("DeleteAlarmFilter-request", log.Fields{"id": *id})
343 if isTestMode(ctx) {
344 out := new(empty.Empty)
345 return out, nil
346 }
347 return nil, errors.New("UnImplemented")
348}
349
350func (handler *APIHandler) SelfTest(ctx context.Context, id *voltha.ID) (*voltha.SelfTestResponse, error) {
351 log.Debugw("SelfTest-request", log.Fields{"id": id})
352 if isTestMode(ctx) {
353 resp := &voltha.SelfTestResponse{Result: voltha.SelfTestResponse_SUCCESS}
354 return resp, nil
355 }
356 return nil, errors.New("UnImplemented")
357}