VOL-4019: Initial commit with grpc nbi, sbi, etcd, kafka and hw management rpcs.

Change-Id: I78feaf7da284028fc61f42c5e0c5f56e72fe9e78
diff --git a/pkg/nbi/hw_mgmt_svc_api.go b/pkg/nbi/hw_mgmt_svc_api.go
new file mode 100644
index 0000000..0bfd82f
--- /dev/null
+++ b/pkg/nbi/hw_mgmt_svc_api.go
@@ -0,0 +1,388 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Package nbi holds rpc server apis implemented
+package nbi
+
+import (
+	"context"
+	"errors"
+	"fmt"
+
+	"github.com/jinzhu/copier"
+	"github.com/opencord/device-management-interface/go/dmi"
+	"github.com/opencord/opendevice-manager/pkg/config"
+	"github.com/opencord/voltha-lib-go/v4/pkg/log"
+
+	dev "github.com/opencord/opendevice-manager/pkg/models/device"
+	hw "github.com/opencord/opendevice-manager/pkg/models/hwcomponents"
+
+	empty "github.com/golang/protobuf/ptypes/empty"
+)
+
+// StartManagingDevice refers to the RPC method invoked for start Managing Device.
+// Initializes context for a device and sets up required states
+func (c *NativeHwManagementService) StartManagingDevice(req *dmi.ModifiableComponent, streamResp dmi.NativeHWManagementService_StartManagingDeviceServer) error {
+	ctx := config.GetNewContextFromGlobalContxt("StartManagingDevice")
+
+	logger.Infow(ctx, "StartManagingDevice-invoked-on-grpc-server", log.Fields{"req": req})
+	defer logger.Infow(ctx, "StartManagingDevice-on-grpc-server-completed", log.Fields{"req": req})
+
+	if errorResp, ok := validateStartManagingDeviceReq(ctx, req); !ok {
+		streamResp.Send(errorResp)
+		return errors.New("failed at validateStartManagingDeviceReq")
+	}
+
+	devRec, err := dev.NewDeviceRecord(ctx, req)
+
+	if err != nil {
+		streamResp.Send(errRespStartManagingDevice(ctx, req, dmi.StartManagingDeviceResponse_INVALID_PARAMS, err))
+		return err
+	}
+
+	adapter, err := connections.getConnection(ctx, devRec)
+
+	if adapter == nil {
+		streamResp.Send(errRespStartManagingDevice(ctx, req, dmi.StartManagingDeviceResponse_INVALID_PARAMS, err))
+		return err
+	}
+
+	devRec.DBAddByName(ctx)
+
+	err, connMade := adapter.StartManagingDevice(ctx, devRec, req, streamResp)
+
+	if !connMade {
+		devRec.DBDelRecord(ctx)
+		adapter.Disconnect(ctx)
+		connections.delConn(ctx, devRec.Name)
+		streamResp.Send(errRespStartManagingDevice(ctx, req, dmi.StartManagingDeviceResponse_UNDEFINED_REASON, err))
+	}
+
+	return err
+}
+
+// StopManagingDevice - Stops management of a device and clean up any context and caches for that device
+// This rpc can be called at any time, even before the StartManagingDevice operation
+// has completed, and should be able to cleanup.
+func (c *NativeHwManagementService) StopManagingDevice(ctx context.Context, req *dmi.StopManagingDeviceRequest) (*dmi.StopManagingDeviceResponse, error) {
+
+	var devRec *dev.DeviceRecord
+	resp := new(dmi.StopManagingDeviceResponse)
+	var err error
+
+	ctx = config.GetNewContextFromContxt(ctx, "StopManagingDevice")
+
+	logger.Infow(ctx, "StopManagingDevice-invoked-on-grpc-server", log.Fields{"req": req})
+	defer logger.Infow(ctx, "StopManagingDevice-on-grpc-server-completed", log.Fields{"req": req})
+
+	if recTmp, err := dev.DBGetByName(ctx, req.Name); recTmp == nil {
+		return errRespStopManagingDevice(ctx, req, dmi.StopManagingDeviceResponse_UNKNOWN_DEVICE, err), err
+	} else {
+		devRec = recTmp
+	}
+
+	defer devRec.DBDelRecord(ctx)
+	defer hw.DBDelAllHwComponents(ctx, devRec.Uuid)
+
+	adapter, err := connections.getConnection(ctx, devRec)
+
+	if adapter != nil {
+		resp, err = adapter.StopManagingDevice(ctx, devRec, req)
+		adapter.Disconnect(ctx)
+		connections.delConn(ctx, devRec.Name)
+	}
+
+	if err != nil {
+		logger.Errorw(ctx, "Errors-at-StopManagingDevice", log.Fields{"req": req, "error": err})
+	}
+
+	return resp, err
+}
+
+// GetManagedDevices - Returns an object containing a list of devices managed by this entity
+func (c *NativeHwManagementService) GetManagedDevices(ctx context.Context, req *empty.Empty) (*dmi.ManagedDevicesResponse, error) {
+	ctx = config.GetNewContextFromContxt(ctx, "GetManagedDevices")
+	resp := new(dmi.ManagedDevicesResponse)
+
+	logger.Infow(ctx, "GetManagedDevices-invoked-on-grpc-server", log.Fields{"req": req})
+	defer logger.Infow(ctx, "GetManagedDevices-on-grpc-server-completed", log.Fields{"req": req})
+
+	listDevRecs, err := dev.DBGetAll(ctx)
+	for _, devRec := range listDevRecs {
+		modComp := new(dmi.ModifiableComponent)
+		err2 := copier.Copy(&modComp, &devRec)
+		if err2 != nil {
+			logger.Errorw(ctx, "Copy-failed-at-GetManagedDevices", log.Fields{"req": req, "rec": devRec, "error": err})
+		} else {
+			modComp.Uri.Uri = devRec.Uri
+			resp.Devices = append(resp.Devices, modComp)
+		}
+	}
+	logger.Infow(ctx, "GetManagedDevices-completed", log.Fields{"req": req, "resp": resp, "error": err})
+	return resp, err
+}
+
+// GetPhysicalInventory - Place Holder for implementation in future
+func (c *NativeHwManagementService) GetPhysicalInventory(req *dmi.PhysicalInventoryRequest, streamResp dmi.NativeHWManagementService_GetPhysicalInventoryServer) error {
+
+	ctx := config.GetNewContextFromGlobalContxt("GetPhysicalInventory")
+
+	logger.Infow(ctx, "GetPhysicalInventory-invoked-on-grpc-server", log.Fields{"req": req})
+	defer logger.Infow(ctx, "GetPhysicalInventory-on-grpc-server-completed", log.Fields{"req": req})
+
+	var devRec *dev.DeviceRecord
+
+	if recTmp, err := dev.DBGetByUuid(ctx, req.DeviceUuid.Uuid); recTmp == nil {
+		streamResp.Send(errRespGetPhysicatInventory(ctx, req, dmi.PhysicalInventoryResponse_UNKNOWN_DEVICE, err))
+		return err
+	} else {
+		devRec = recTmp
+	}
+
+	adapter, err := connections.getConnection(ctx, devRec)
+	if adapter == nil {
+		streamResp.Send(errRespGetPhysicatInventory(ctx, req, dmi.PhysicalInventoryResponse_DEVICE_UNREACHABLE, err))
+		return err
+	}
+
+	err = adapter.GetPhysicalInventory(ctx, devRec, req, streamResp)
+
+	if err != nil {
+		logger.Errorw(ctx, "Errors-at-GetPhysicalInventory", log.Fields{"req": req, "error": err})
+	}
+
+	return err
+}
+
+// GetHWComponentInfo - refers to the RPC method invoked for get the details of a particular HW component
+func (c *NativeHwManagementService) GetHWComponentInfo(req *dmi.HWComponentInfoGetRequest, streamResp dmi.NativeHWManagementService_GetHWComponentInfoServer) error {
+	ctx := config.GetNewContextFromGlobalContxt("GetHWComponentInfo")
+
+	logger.Infow(ctx, "GetHWComponentInfo-invoked-on-grpc-server", log.Fields{"req": req})
+	defer logger.Infow(ctx, "GetHWComponentInfo-on-grpc-server-completed", log.Fields{"req": req})
+
+	devRec, err := dev.DBGetByUuid(ctx, req.DeviceUuid.Uuid)
+	if devRec == nil {
+		streamResp.Send(errRespGetHWComponentInfo(ctx, req, dmi.HWComponentInfoGetResponse_UNKNOWN_DEVICE, err))
+		return err
+	}
+
+	hwCompRec, err := hw.DBGetRecByUuid(ctx, req.DeviceUuid.Uuid, req.ComponentUuid.Uuid)
+	if hwCompRec == nil {
+		streamResp.Send(errRespGetHWComponentInfo(ctx, req, dmi.HWComponentInfoGetResponse_UNKNOWN_DEVICE, err))
+		return err
+	}
+
+	adapter, err := connections.getConnection(ctx, devRec)
+	if adapter == nil {
+		streamResp.Send(errRespGetHWComponentInfo(ctx, req, dmi.HWComponentInfoGetResponse_DEVICE_UNREACHABLE, err))
+		return err
+	}
+
+	err = adapter.GetHWComponentInfo(ctx, devRec.Uuid, hwCompRec, req, streamResp)
+	if err != nil {
+		logger.Errorw(ctx, "Errors-at-GetHWComponentInfo", log.Fields{"req": req, "error": err})
+	}
+	return err
+}
+
+// SetHWComponentInfo is the nb api exposed for receiving SetHWComponentInfo from NEM
+func (c *NativeHwManagementService) SetHWComponentInfo(ctx context.Context, req *dmi.HWComponentInfoSetRequest) (*dmi.HWComponentInfoSetResponse, error) {
+	ctx = config.GetNewContextFromContxt(ctx, "SetHWComponentInfo")
+
+	logger.Infow(ctx, "SetHWComponentInfo-invoked-on-grpc-server", log.Fields{"req": req})
+	defer logger.Infow(ctx, "SetHWComponentInfo-on-grpc-server-completed", log.Fields{"req": req})
+
+	var devRec *dev.DeviceRecord
+	var hwCompRec *hw.HwCompRecord
+	var err error
+
+	if devRec, err = dev.DBGetByUuid(ctx, req.DeviceUuid.Uuid); devRec == nil {
+		return errRespSetHWComponentInfo(ctx, req, dmi.HWComponentInfoSetResponse_UNKNOWN_DEVICE, err), err
+	}
+
+	if hwCompRec, err = hw.DBGetRecByUuid(ctx, req.DeviceUuid.Uuid, req.ComponentUuid.Uuid); hwCompRec == nil {
+		return errRespSetHWComponentInfo(ctx, req, dmi.HWComponentInfoSetResponse_UNKNOWN_DEVICE, err), err
+	}
+
+	adapter, err := connections.getConnection(ctx, devRec)
+	if adapter == nil {
+		return errRespSetHWComponentInfo(ctx, req, dmi.HWComponentInfoSetResponse_DEVICE_UNREACHABLE, err), err
+	}
+
+	resp, err := adapter.SetHWComponentInfo(ctx, devRec.Uuid, hwCompRec, req)
+
+	if err != nil {
+		logger.Errorw(ctx, "Errors-at-SetHWComponentInfo", log.Fields{"req": req, "error": err})
+	}
+
+	return resp, err
+}
+
+// SetLoggingEndpoint - refers to the RPC method invoked for set the location to which logs need to be shipped
+func (c *NativeHwManagementService) SetLoggingEndpoint(ctx context.Context, req *dmi.SetLoggingEndpointRequest) (*dmi.SetRemoteEndpointResponse, error) {
+	ctx = config.GetNewContextFromGlobalContxt("SetLoggingEndpoint")
+
+	logger.Infow(ctx, "SetLoggingEndpoint-invoked-on-grpc-server", log.Fields{"req": req})
+	defer logger.Infow(ctx, "SetLoggingEndpoint-on-grpc-server-completed", log.Fields{"req": req})
+
+	// Check device is there or not by Uuid
+	devRec, err := dev.DBGetByUuid(ctx, req.DeviceUuid.Uuid)
+	if err != nil {
+		return errRespSetLoggingEndpoint(ctx, req, dmi.SetRemoteEndpointResponse_UNKNOWN_DEVICE, err), err
+	}
+
+	adapter, err2 := connections.getConnection(ctx, devRec)
+	if adapter == nil {
+		return errRespSetLoggingEndpoint(ctx, req, dmi.SetRemoteEndpointResponse_DEVICE_UNREACHABLE, err2), err2
+	}
+
+	resp, err := adapter.SetLoggingEndpoint(ctx, devRec, req)
+	if err != nil {
+		logger.Errorw(ctx, "Errors-at-SetLoggingEndpoint", log.Fields{"req": req, "error": err})
+	}
+
+	return resp, err
+}
+
+// GetLoggingEndpoint - refers to the RPC method invoked for get the location to which logs need to be shipped
+func (c *NativeHwManagementService) GetLoggingEndpoint(ctx context.Context, req *dmi.HardwareID) (*dmi.GetLoggingEndpointResponse, error) {
+	ctx = config.GetNewContextFromGlobalContxt("GetLoggingEndpoint")
+
+	logger.Infow(ctx, "GetLoggingEndpoint-invoked-on-grpc-server", log.Fields{"req": req})
+	defer logger.Infow(ctx, "GetLoggingEndpoint-on-grpc-server-completed", log.Fields{"req": req})
+
+	// Check device is there or not by Uuid
+	devRec, err := dev.DBGetByUuid(ctx, req.Uuid.Uuid)
+	if err != nil {
+		return errRespGetLoggingEndpoint(ctx, req, dmi.GetLoggingEndpointResponse_UNKNOWN_DEVICE, err), err
+	}
+
+	adapter, err := connections.getConnection(ctx, devRec)
+	if adapter == nil {
+		return errRespGetLoggingEndpoint(ctx, req, dmi.GetLoggingEndpointResponse_DEVICE_UNREACHABLE, err), err
+	}
+
+	resp, err := adapter.GetLoggingEndpoint(ctx, devRec, req)
+	if err != nil {
+		logger.Errorw(ctx, "Errors-at-GetLoggingEndpoint", log.Fields{"req": req, "error": err})
+	}
+	return resp, err
+}
+
+// SetMsgBusEndpoint - Place Holder for implementation in future
+func (c *NativeHwManagementService) SetMsgBusEndpoint(ctx context.Context, req *dmi.SetMsgBusEndpointRequest) (*dmi.SetRemoteEndpointResponse, error) {
+	errMsg := "SetMsgBusEndpoint not yet implemented"
+	fmt.Println(errMsg)
+	return nil, errors.New(errMsg)
+}
+
+// GetMsgBusEndpoint - Place Holder for implementation in future
+func (c *NativeHwManagementService) GetMsgBusEndpoint(ctx context.Context, req *empty.Empty) (*dmi.GetMsgBusEndpointResponse, error) {
+	errMsg := "GetMsgBusEndpoint not yet implemented"
+	fmt.Println(errMsg)
+	return nil, errors.New(errMsg)
+}
+
+// GetLoggableEntities refers to the grpc northbound interface exposed for getting loggable entities from device
+func (c *NativeHwManagementService) GetLoggableEntities(ctx context.Context, req *dmi.GetLoggableEntitiesRequest) (*dmi.GetLogLevelResponse, error) {
+
+	ctx = config.GetNewContextFromContxt(ctx, "GetLoggableEntities")
+	resp := new(dmi.GetLogLevelResponse)
+	resp.DeviceUuid = req.DeviceUuid
+
+	logger.Infow(ctx, "GetLoggableEntities-invoked-on-grpc-server", log.Fields{"req": req})
+	defer logger.Infow(ctx, "GetLoggableEntities-on-grpc-server-completed", log.Fields{"req": req})
+
+	devRec, err := dev.DBGetByUuid(ctx, req.DeviceUuid.Uuid)
+	if err != nil {
+		return errRespGetLoggableEntities(ctx, req, dmi.GetLogLevelResponse_UNKNOWN_DEVICE, err), err
+	}
+
+	if devRec.Logging.LoggableEntities != nil {
+		resp.Status = dmi.Status_OK_STATUS
+		resp.LogLevels, _ = devRec.GetLoggableEntitiesFromDevRec(ctx, nil)
+		return resp, nil
+	}
+
+	adapter, err := connections.getConnection(ctx, devRec)
+	if adapter == nil {
+		return errRespGetLoggableEntities(ctx, req, dmi.GetLogLevelResponse_DEVICE_UNREACHABLE, err), err
+	}
+
+	return adapter.GetLoggableEntities(ctx, devRec, req)
+}
+
+// SetLogLevel refers to the grpc northbound interface exposed for setting log level for entities
+func (c *NativeHwManagementService) SetLogLevel(ctx context.Context, req *dmi.SetLogLevelRequest) (*dmi.SetLogLevelResponse, error) {
+
+	ctx = config.GetNewContextFromContxt(ctx, "SetLogLevel")
+	resp := new(dmi.SetLogLevelResponse)
+	resp.DeviceUuid = req.DeviceUuid
+
+	logger.Infow(ctx, "SetLogLevel-invoked-on-grpc-server", log.Fields{"req": req})
+	defer logger.Infow(ctx, "SetLogLevel-on-grpc-server-completed", log.Fields{"req": req})
+
+	// validate request
+	if ok, err := isValidSetLogLevel(ctx, req.Loglevels); ok {
+		return errRespSetLogLevel(ctx, req, dmi.SetLogLevelResponse_UNKNOWN_LOG_ENTITY, err), err
+	}
+
+	devRec, err := dev.DBGetByUuid(ctx, req.DeviceUuid.Uuid)
+	if err != nil {
+		return errRespSetLogLevel(ctx, req, dmi.SetLogLevelResponse_UNKNOWN_DEVICE, err), err
+	}
+
+	adapter, err := connections.getConnection(ctx, devRec)
+	if adapter == nil {
+		return errRespSetLogLevel(ctx, req, dmi.SetLogLevelResponse_DEVICE_UNREACHABLE, err), err
+	}
+
+	return adapter.SetLogLevel(ctx, devRec, req)
+}
+
+// GetLogLevel refers to the grpc northbound interface exposed for getting log level of entities
+func (c *NativeHwManagementService) GetLogLevel(ctx context.Context, req *dmi.GetLogLevelRequest) (*dmi.GetLogLevelResponse, error) {
+
+	ctx = config.GetNewContextFromContxt(ctx, "GetLogLevel")
+	resp := new(dmi.GetLogLevelResponse)
+	resp.DeviceUuid = req.DeviceUuid
+
+	logger.Infow(ctx, "GetLogLevel-invoked-on-grpc-server", log.Fields{"req": req})
+	defer logger.Infow(ctx, "GetLogLevel-on-grpc-server-completed", log.Fields{"req": req})
+
+	devRec, err := dev.DBGetByUuid(ctx, req.DeviceUuid.Uuid)
+	if err != nil {
+		return errRespGetLogLevel(ctx, req, dmi.GetLogLevelResponse_UNKNOWN_DEVICE, err), err
+	}
+
+	if devRec.Logging.LoggableEntities != nil {
+
+		if output, ok := devRec.GetLoggableEntitiesFromDevRec(ctx, req.Entities); ok {
+			resp.Status = dmi.Status_OK_STATUS
+			resp.LogLevels = output
+			return resp, nil
+		}
+
+	}
+
+	adapter, err := connections.getConnection(ctx, devRec)
+	if adapter == nil {
+		return errRespGetLogLevel(ctx, req, dmi.GetLogLevelResponse_DEVICE_UNREACHABLE, err), err
+	}
+
+	return adapter.GetLogLevel(ctx, devRec, req)
+}