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

Change-Id: I78feaf7da284028fc61f42c5e0c5f56e72fe9e78
diff --git a/pkg/nbi/common.go b/pkg/nbi/common.go
new file mode 100644
index 0000000..4f80e8c
--- /dev/null
+++ b/pkg/nbi/common.go
@@ -0,0 +1,92 @@
+/*
+ * 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"
+	"net"
+	"os"
+
+	"github.com/opencord/opendevice-manager/pkg/config"
+
+	"github.com/opencord/device-management-interface/go/dmi"
+
+	"github.com/opencord/voltha-lib-go/v4/pkg/log"
+	g "google.golang.org/grpc"
+	"google.golang.org/grpc/credentials"
+	"google.golang.org/grpc/reflection"
+)
+
+// logger represents the log object
+var logger log.CLogger
+
+// grpcServer refers to object which holds grpc serevr
+var grpcServer *g.Server
+
+// init function for the package
+func init() {
+	logger = config.Initlog()
+	initConnectMap()
+}
+
+func registerServers(grpcServer *g.Server) {
+	hwMgmtSvc := new(NativeHwManagementService)
+	dmi.RegisterNativeHWManagementServiceServer(grpcServer, hwMgmtSvc)
+	reflection.Register(grpcServer)
+}
+
+// StartGrpcServer starts the grpc server for listening to NEM requests
+func StartGrpcServer(ctx context.Context) {
+	coreFlags := config.GetCoreFlags()
+	lis, err := net.Listen("tcp", coreFlags.GrpcEndPoint)
+	if err != nil {
+		logger.Error(ctx, "Failed-to-listen-on-Grpc-Port", log.Fields{"grpc-flags": coreFlags.GrpcFlags, "error": err})
+		os.Exit(1)
+	}
+
+	if coreFlags.SecureConnection {
+		creds, err := credentials.NewServerTLSFromFile(coreFlags.ServerCrt, coreFlags.ServerKey)
+		if err != nil {
+			logger.Error(ctx, "could-not-process-the-credentials", log.Fields{"error": err})
+		}
+		grpcServer = g.NewServer(g.Creds(creds))
+	} else {
+		grpcServer = g.NewServer()
+	}
+
+	registerServers(grpcServer)
+
+	logger.Infow(ctx, "Grpc-server-starting", log.Fields{"grpc-server-info": grpcServer, "grpc-env-info": coreFlags.GrpcFlags, "is-secure-conn": coreFlags.SecureConnection})
+
+	// Starting the server
+	if err := grpcServer.Serve(lis); err != nil {
+		logger.Errorw(ctx, "Failed-to-start-Grpc-Server", log.Fields{"server": coreFlags.GrpcFlags, "error": err})
+		os.Exit(1)
+	}
+
+	logger.Infow(ctx, "grpc-server-stopped-successfully", log.Fields{"grpc-server-info": grpcServer, "grpc-env-info": coreFlags.GrpcFlags})
+
+}
+
+// StopGrpcServer tear down the gRPC connection from opendevice manager to NEM
+func StopGrpcServer(ctx context.Context) {
+	if grpcServer != nil {
+		grpcServer.GracefulStop()
+	}
+	logger.Infow(ctx, "grpc-server-teardown-success", log.Fields{"grpc-server-info": grpcServer})
+}
diff --git a/pkg/nbi/connection.go b/pkg/nbi/connection.go
new file mode 100644
index 0000000..ae94999
--- /dev/null
+++ b/pkg/nbi/connection.go
@@ -0,0 +1,88 @@
+/*
+ * 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"
+	"sync"
+
+	dev "github.com/opencord/opendevice-manager/pkg/models/device"
+	"github.com/opencord/opendevice-manager/pkg/sbi"
+	"github.com/opencord/voltha-lib-go/v4/pkg/log"
+)
+
+// connectMap store all device connections established
+type connectMap struct {
+	nameToAdapter map[string]sbi.Adapter // key is name and value is adapter
+	mutex         *sync.RWMutex          // mutex is used to lock when accessing
+}
+
+var connections *connectMap
+
+// initConnectMap initialises map for storing connections
+func initConnectMap() {
+	connections = new(connectMap)
+	connections.nameToAdapter = make(map[string]sbi.Adapter)
+	connections.mutex = &sync.RWMutex{}
+}
+
+// DeInitConnectMap clears all stored connections
+func DeInitConnectMap(ctx context.Context) {
+	connections.nameToAdapter = nil
+	connections.mutex = nil
+	connections = nil
+}
+
+// getConnection retrieves connection object from map using name
+func (conn *connectMap) getConnection(ctx context.Context, devRec *dev.DeviceRecord) (sbi.Adapter, error) {
+	conn.mutex.Lock()
+	defer conn.mutex.Unlock()
+	if val, ok := conn.nameToAdapter[devRec.Name]; ok {
+		return val, nil
+	}
+
+	// Get the right adapter
+	adapter := sbi.GetHwMgmtSvcClient(devRec)
+	if err := adapter.Connect(ctx); err != nil {
+		return nil, err
+	}
+
+	conn.nameToAdapter[devRec.Name] = adapter
+	logger.Infow(ctx, "getConnection-completed", log.Fields{"name": devRec.Name, "adapter": adapter})
+
+	return adapter, nil
+}
+
+// // storeConn stores connection object in map using uuid and name
+// func (conn *connectMap) storeConnWithName(ctx context.Context, name string, adapter sbi.Adapter) {
+// 	conn.mutex.Lock()
+// 	defer conn.mutex.Unlock()
+// 	conn.nameToAdapter[name] = adapter
+// 	logger.Infow(ctx, "storeConnWithName-completed", log.Fields{"name": name, "adapter": adapter})
+// }
+
+// delConn deletes connection object from map using uuid and name
+func (conn *connectMap) delConn(ctx context.Context, name string) {
+	conn.mutex.Lock()
+	defer conn.mutex.Unlock()
+
+	if name != "" {
+		delete(conn.nameToAdapter, name)
+	}
+	logger.Infow(ctx, "delConn-completed", log.Fields{"name": name})
+}
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)
+}
diff --git a/pkg/nbi/hw_mgmt_svc_err_resp.go b/pkg/nbi/hw_mgmt_svc_err_resp.go
new file mode 100644
index 0000000..ab0c517
--- /dev/null
+++ b/pkg/nbi/hw_mgmt_svc_err_resp.go
@@ -0,0 +1,128 @@
+/*
+ * 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"
+
+	"github.com/opencord/device-management-interface/go/dmi"
+	"github.com/opencord/voltha-lib-go/v4/pkg/log"
+)
+
+// errRespStartManagingDevice represents the func to construct error response for rpc StartManagingDevice
+func errRespStartManagingDevice(ctx context.Context, req *dmi.ModifiableComponent, reason dmi.StartManagingDeviceResponse_Reason, err error) *dmi.StartManagingDeviceResponse {
+	resp := new(dmi.StartManagingDeviceResponse)
+	resp.Status = dmi.Status_ERROR_STATUS
+	resp.Reason = reason
+	resp.ReasonDetail = err.Error()
+	logger.Errorw(ctx, "StartManagingDevice-on-grpc-server-failed", log.Fields{"req": req, "resp": resp, "error": err})
+	return resp
+}
+
+// errRespStopManagingDevice represents the func to construct error response for rpc StopManagingDevice
+func errRespStopManagingDevice(ctx context.Context, req *dmi.StopManagingDeviceRequest, reason dmi.StopManagingDeviceResponse_Reason, err error) *dmi.StopManagingDeviceResponse {
+	resp := new(dmi.StopManagingDeviceResponse)
+	resp.Status = dmi.Status_ERROR_STATUS
+	resp.Reason = reason
+	resp.ReasonDetail = err.Error()
+	logger.Errorw(ctx, "StopManagingDevice-on-grpc-server-failed", log.Fields{"req": req, "resp": resp, "error": err})
+	return resp
+}
+
+// errRespGetPhysicatInventory represents the func to construct error response for rpc GetPhysicatInventory
+func errRespGetPhysicatInventory(ctx context.Context, req *dmi.PhysicalInventoryRequest, reason dmi.PhysicalInventoryResponse_Reason, err error) *dmi.PhysicalInventoryResponse {
+	resp := new(dmi.PhysicalInventoryResponse)
+	resp.Status = dmi.Status_ERROR_STATUS
+	resp.Reason = reason
+	resp.ReasonDetail = err.Error()
+	logger.Errorw(ctx, "GetPhysicatInventory-on-grpc-server-failed", log.Fields{"req": req, "resp": resp, "error": err})
+	return resp
+}
+
+// errRespGetHWComponentInfo represents the func to construct error response for rpc GetHWComponentInfo
+func errRespGetHWComponentInfo(ctx context.Context, req *dmi.HWComponentInfoGetRequest, reason dmi.HWComponentInfoGetResponse_Reason, err error) *dmi.HWComponentInfoGetResponse {
+	resp := new(dmi.HWComponentInfoGetResponse)
+	resp.Status = dmi.Status_ERROR_STATUS
+	resp.Reason = reason
+	resp.ReasonDetail = err.Error()
+	logger.Errorw(ctx, "GetHWComponentInfo-on-grpc-server-failed", log.Fields{"req": req, "resp": resp, "error": err})
+	return resp
+}
+
+// errRespSetHWComponentInfo represents the func to construct error response for rpc SetHWComponentInfo
+func errRespSetHWComponentInfo(ctx context.Context, req *dmi.HWComponentInfoSetRequest, reason dmi.HWComponentInfoSetResponse_Reason, err error) *dmi.HWComponentInfoSetResponse {
+	resp := new(dmi.HWComponentInfoSetResponse)
+	resp.Status = dmi.Status_ERROR_STATUS
+	resp.Reason = reason
+	resp.ReasonDetail = err.Error()
+	logger.Errorw(ctx, "SetHWComponentInfo-on-grpc-server-failed", log.Fields{"req": req, "resp": resp, "error": err})
+	return resp
+}
+
+// errRespSetLoggingEndpoint represents the func to construct error response for rpc SetLoggingEndpoint
+func errRespSetLoggingEndpoint(ctx context.Context, req *dmi.SetLoggingEndpointRequest, reason dmi.SetRemoteEndpointResponse_Reason, err error) *dmi.SetRemoteEndpointResponse {
+	resp := new(dmi.SetRemoteEndpointResponse)
+	resp.Status = dmi.Status_ERROR_STATUS
+	resp.Reason = reason
+	resp.ReasonDetail = err.Error()
+	logger.Errorw(ctx, "SetLoggingEndpoint-on-grpc-server-failed", log.Fields{"req": req, "resp": resp, "error": err})
+	return resp
+}
+
+// errRespGetLoggingEndpoint represents the func to construct error response for rpc GetLoggingEndpoint
+func errRespGetLoggingEndpoint(ctx context.Context, req *dmi.HardwareID, reason dmi.GetLoggingEndpointResponse_Reason, err error) *dmi.GetLoggingEndpointResponse {
+	resp := new(dmi.GetLoggingEndpointResponse)
+	resp.Status = dmi.Status_ERROR_STATUS
+	resp.Reason = reason
+	resp.ReasonDetail = err.Error()
+	logger.Errorw(ctx, "GetLoggingEndpoint-on-grpc-server-failed", log.Fields{"req": req, "resp": resp, "error": err})
+	return resp
+}
+
+// errRespGetLoggableEntities represents the func to construct error response for rpc GetLoggableEntities
+func errRespGetLoggableEntities(ctx context.Context, req *dmi.GetLoggableEntitiesRequest, reason dmi.GetLogLevelResponse_Reason, err error) *dmi.GetLogLevelResponse {
+	resp := new(dmi.GetLogLevelResponse)
+	resp.DeviceUuid = req.DeviceUuid
+	resp.Status = dmi.Status_ERROR_STATUS
+	resp.Reason = reason
+	resp.ReasonDetail = err.Error()
+	logger.Errorw(ctx, "GetLoggableEntities-on-grpc-server-failed", log.Fields{"req": req, "resp": resp, "error": err})
+	return resp
+}
+
+// errRespSetLogLevel represents the func to construct error response for rpc SetLogLevel
+func errRespSetLogLevel(ctx context.Context, req *dmi.SetLogLevelRequest, reason dmi.SetLogLevelResponse_Reason, err error) *dmi.SetLogLevelResponse {
+	resp := new(dmi.SetLogLevelResponse)
+	resp.DeviceUuid = req.DeviceUuid
+	resp.Status = dmi.Status_ERROR_STATUS
+	resp.Reason = reason
+	resp.ReasonDetail = err.Error()
+	logger.Errorw(ctx, "SetLogLevel-on-grpc-server-failed", log.Fields{"req": req, "resp": resp, "error": err})
+	return resp
+}
+
+// errRespGetLogLevel represents the func to construct error response for rpc GetLogLevel
+func errRespGetLogLevel(ctx context.Context, req *dmi.GetLogLevelRequest, reason dmi.GetLogLevelResponse_Reason, err error) *dmi.GetLogLevelResponse {
+	resp := new(dmi.GetLogLevelResponse)
+	resp.DeviceUuid = req.DeviceUuid
+	resp.Status = dmi.Status_ERROR_STATUS
+	resp.Reason = reason
+	resp.ReasonDetail = err.Error()
+	logger.Errorw(ctx, "GetLogLevel-on-grpc-server-failed", log.Fields{"req": req, "resp": resp, "error": err})
+	return resp
+}
diff --git a/pkg/nbi/server_structs.go b/pkg/nbi/server_structs.go
new file mode 100644
index 0000000..8811397
--- /dev/null
+++ b/pkg/nbi/server_structs.go
@@ -0,0 +1,22 @@
+/*
+ * 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
+
+// NativeHwManagementService refers to the struct defined for Service NativeHwManagementService
+type NativeHwManagementService struct {
+}
diff --git a/pkg/nbi/util.go b/pkg/nbi/util.go
new file mode 100644
index 0000000..d8af7cc
--- /dev/null
+++ b/pkg/nbi/util.go
@@ -0,0 +1,108 @@
+/*
+ * 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"
+	"net"
+	"strconv"
+	"strings"
+
+	"github.com/opencord/device-management-interface/go/dmi"
+	dev "github.com/opencord/opendevice-manager/pkg/models/device"
+
+	"github.com/opencord/voltha-lib-go/v4/pkg/log"
+)
+
+/* validateUri() verifies if the ip and port are valid and already registered then return the truth value of the desired state specified by the following 2 switches,
+   wantRegistered: 'true' if the fact of an ip is registered is the desired state
+   includePort: 'true' further checks if <ip>:<port#> does exist in the devicemap in case an ip is found registered
+*/
+func validateUri(ctx context.Context, uri string) (ok bool, err error) {
+	ok = false
+	if !strings.Contains(uri, ":") {
+		logger.Errorw(ctx, "Invalid-uri", log.Fields{"uri-received": uri, "expected-uri": "ip:port"})
+		err = errors.New("incorrect IP address format (<ip>:<port #>)")
+		return
+	}
+	splits := strings.Split(uri, ":")
+	ip, port := splits[0], splits[1]
+	if net.ParseIP(ip) == nil {
+		// also check to see if it's a valid hostname
+		if _, err2 := net.LookupIP(ip); err2 != nil {
+			logger.Errorw(ctx, "Invalid-ip", log.Fields{"uri-received": uri, "ip": ip})
+			err = errors.New("invalid IP address " + ip)
+			return
+		}
+	}
+	if _, err2 := strconv.Atoi(port); err2 != nil {
+		logger.Errorw(ctx, "Invalid-port", log.Fields{"uri-received": uri, "port": port})
+		err = errors.New("Port number " + port + " needs to be an integer")
+		return
+	}
+	ok = true
+	return
+}
+
+// validateStartManagingDeviceReq validates the 'StartManagingDevice' request is proper or not
+func validateStartManagingDeviceReq(ctx context.Context, req *dmi.ModifiableComponent) (resp *dmi.StartManagingDeviceResponse, ok bool) {
+	resp = new(dmi.StartManagingDeviceResponse)
+	resp.DeviceUuid = new(dmi.Uuid)
+	resp.Status = dmi.Status_ERROR_STATUS
+	if ok1, err := validateUri(ctx, req.Uri.Uri); !ok1 {
+		logger.Errorw(ctx, "validation-failed-for-StartManagingDevice-request", log.Fields{"error": err, "req": req})
+		resp.Reason = dmi.StartManagingDeviceResponse_INVALID_PARAMS
+		resp.ReasonDetail = err.Error()
+		return
+	}
+
+	if rec, _ := dev.DBGetByName(ctx, req.Name); rec != nil {
+		logger.Errorw(ctx, "validation-failed-for-StartManagingDevice-request-record-already-exists", log.Fields{"req": req, "rec": rec})
+		resp.Reason = dmi.StartManagingDeviceResponse_DEVICE_ALREADY_MANAGED
+		resp.ReasonDetail = "device already exists and managed with uuid " + rec.Uuid + " and uri " + rec.Uri
+		return
+	}
+
+	ok = true
+
+	return
+}
+
+// isValidSetLogLevel check is valid set loglevel request
+func isValidSetLogLevel(ctx context.Context, listEntities []*dmi.EntitiesLogLevel) (bool, error) {
+
+	if len(listEntities) == 0 {
+		// atleast one entities is required for set loglevel
+		logger.Errorw(ctx, "found-empty-entities", log.Fields{"entities": listEntities})
+		return false, errors.New("found empty entities")
+	}
+
+	if len(listEntities) > 1 {
+		// if set Entities more than 1, atleast 1 entity in nested struct
+		for _, entities := range listEntities {
+			if len(entities.Entities) == 0 {
+				logger.Errorw(ctx, "entities-has-empty-entries", log.Fields{"entities": entities})
+				return false, errors.New("set-empty-entries-not-allowed")
+			}
+		}
+	}
+
+	logger.Debug(ctx, "valid-set-log-request")
+	return true, nil
+}