blob: ba5a0c4aceda0c2a2859ad215703ce5b59372251 [file] [log] [blame]
amit.ghosh258d14c2020-10-02 15:13:38 +02001/*
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 */
16
17package dmiserver
18
19import (
20 "context"
21 "fmt"
22
23 "github.com/golang/protobuf/ptypes/empty"
24 "github.com/golang/protobuf/ptypes/timestamp"
25 "github.com/opencord/bbsim/internal/bbsim/devices"
26 "github.com/opencord/bbsim/internal/common"
27 dmi "github.com/opencord/device-management-interface/go/dmi"
28
29 guuid "github.com/google/uuid"
30 "google.golang.org/grpc/codes"
31 "google.golang.org/grpc/status"
32)
33
34func getUUID(seed string) string {
35 return guuid.NewMD5(guuid.Nil, []byte(seed)).String()
36}
37
38//StartManagingDevice establishes connection with the device and does checks to ascertain if the device with passed identity can be managed
39func (dms *DmiAPIServer) StartManagingDevice(req *dmi.ModifiableComponent, stream dmi.NativeHWManagementService_StartManagingDeviceServer) error {
40 //Get serial number and generate the UUID based on this serial number. Store this UUID in local cache
41 logger.Debugf("StartManagingDevice() invoked with request %+v", req)
42 if req == nil {
43 return status.Errorf(codes.FailedPrecondition, "request is empty")
44 }
45
46 if req.Name == "" {
47 return status.Errorf(codes.InvalidArgument, "'Name' can not be empty in the request")
48 }
49
50 olt := devices.GetOLT()
51
52 // Uri is the IP address
53 dms.ipAddress = req.GetUri().GetUri()
54 dms.deviceSerial = olt.SerialNumber
55 dms.deviceName = fmt.Sprintf("%s-%s", common.Config.Olt.Vendor, dms.deviceSerial)
56
57 dms.uuid = getUUID(dms.deviceSerial)
58
59 dms.ponTransceiverUuids = make([]string, olt.NumPon)
60 dms.ponTransceiverCageUuids = make([]string, olt.NumPon)
61
62 var components []*dmi.Component
63
64 // Create and store the component for transceivers and transceiver cages
65 for i := 0; i < olt.NumPon; i++ {
66 label := fmt.Sprintf("pon-%d", olt.Pons[i].ID)
67 dms.ponTransceiverUuids[i] = getUUID(dms.deviceSerial + label)
68 dms.ponTransceiverCageUuids[i] = getUUID(dms.deviceSerial + "cage" + label)
69
70 transName := fmt.Sprintf("sfp-%d", i)
71 cageName := fmt.Sprintf("cage-%d", i)
72
73 trans := dmi.Component{
74 Name: transName,
75 Class: dmi.ComponentType_COMPONENT_TYPE_TRANSCEIVER,
76 Description: "XGS-PON",
77 Uuid: &dmi.Uuid{
78 Uuid: dms.ponTransceiverUuids[i],
79 },
80 Parent: cageName,
81 }
82
83 cage := dmi.Component{
84 Name: cageName,
85 Class: dmi.ComponentType_COMPONENT_TYPE_CONTAINER,
86 Description: "cage",
87 Uuid: &dmi.Uuid{
88 Uuid: dms.ponTransceiverCageUuids[i],
89 },
90 Parent: dms.deviceName,
91 Children: []*dmi.Component{&trans},
92 }
93
94 components = append(components, &cage)
95 }
96
97 dms.components = components
98
99 logger.Debugf("Generated UUID for the uri %s is %s", dms.ipAddress, dms.uuid)
100 response := &dmi.StartManagingDeviceResponse{
101 Status: dmi.Status_OK,
102 DeviceUuid: &dmi.Uuid{
103 Uuid: dms.uuid,
104 },
105 }
106
107 err := stream.Send(response)
108 if err != nil {
109 logger.Errorf("Error while sending response to client %v", err.Error())
110 return status.Errorf(codes.Unknown, err.Error())
111 }
112
113 return nil
114}
115
116//StopManagingDevice stops management of a device and cleans up any context and caches for that device
117func (dms *DmiAPIServer) StopManagingDevice(context.Context, *dmi.StopManagingDeviceRequest) (*dmi.StopManagingDeviceResponse, error) {
118 return nil, status.Errorf(codes.Unimplemented, "rpc StopManagingDevice not implemented")
119}
120
121//GetPhysicalInventory gets the HW inventory details of the Device
122func (dms *DmiAPIServer) GetPhysicalInventory(req *dmi.PhysicalInventoryRequest, stream dmi.NativeHWManagementService_GetPhysicalInventoryServer) error {
123 if req == nil || req.DeviceUuid == nil || req.DeviceUuid.Uuid == "" {
124 return status.Errorf(codes.InvalidArgument, "device-UUID missing in the request")
125 }
126
127 // Function to send the response back on the stream
128 sendResponseBackOnStream := func(stream dmi.NativeHWManagementService_GetPhysicalInventoryServer, msg *dmi.PhysicalInventoryResponse) error {
129 err := stream.Send(msg)
130 if err != nil {
131 logger.Errorf("Error sending response to client, error: %v", err)
132 return status.Errorf(codes.Internal, "Error sending response to client "+err.Error())
133 }
134 return nil
135 }
136
137 if req.DeviceUuid.Uuid != dms.uuid {
138 logger.Errorf("Requested uuid =%s, uuid of existing device = %s", req.DeviceUuid.Uuid, dms.uuid)
139 // Wrong uuid, return error
140 errResponse := &dmi.PhysicalInventoryResponse{
141 Status: dmi.Status_ERROR,
142 Reason: dmi.Reason_UNKNOWN_DEVICE,
143 Inventory: &dmi.Hardware{},
144 }
145
146 return sendResponseBackOnStream(stream, errResponse)
147 }
148
149 response := &dmi.PhysicalInventoryResponse{
150 Status: dmi.Status_OK,
151 Inventory: &dmi.Hardware{
152 LastChange: &timestamp.Timestamp{
153 Seconds: 0,
154 Nanos: 0,
155 },
156 Root: &dmi.Component{
157 Name: dms.deviceName,
158 Class: 0,
159 Description: "",
160 Parent: "",
161 ParentRelPos: 0,
162 Children: dms.components,
163 SerialNum: dms.deviceSerial,
164 MfgName: common.Config.Olt.Vendor,
165 IsFru: false,
166 Uri: &dmi.Uri{
167 Uri: dms.ipAddress,
168 },
169 Uuid: &dmi.Uuid{
170 Uuid: dms.uuid,
171 },
172 State: &dmi.ComponentState{},
173 },
174 },
175 }
176 return sendResponseBackOnStream(stream, response)
177}
178
179//Contains tells whether arr contains element.
180func Contains(arr []string, element string) bool {
181 for _, item := range arr {
182 logger.Debugf("Checking in Contains slice elem = %v str = %s", item, element)
183 if element == item {
184 return true
185 }
186 }
187 return false
188}
189
190func findComponent(l []*dmi.Component, compUUID string) *dmi.Component {
191 for _, comp := range l {
192 logger.Debugf("findComponent slice comp = %v compUUID = %s", comp, compUUID)
193 if comp.Uuid.Uuid == compUUID {
194 return comp
195 }
196
197 for _, child := range comp.GetChildren() {
198 logger.Debugf("findComponent Child slice comp = %v compUUID = %s", comp, compUUID)
199 if child.Uuid.Uuid == compUUID {
200 return child
201 }
202 }
203 }
204
205 return nil
206}
207
208func sendGetHWComponentResponse(c *dmi.Component, stream dmi.NativeHWManagementService_GetHWComponentInfoServer) error {
209 apiStatus := dmi.Status_OK
210 reason := dmi.Reason_UNDEFINED_REASON
211
212 if c == nil {
213 apiStatus = dmi.Status_ERROR
214 reason = dmi.Reason_UNKNOWN_DEVICE
215 }
216
217 response := &dmi.HWComponentInfoGetResponse{
218 Status: apiStatus,
219 Reason: reason,
220 Component: c,
221 }
222
223 err := stream.Send(response)
224 if err != nil {
225 logger.Errorf("Error sending response to client, error: %v", err)
226 return status.Errorf(codes.Internal, "Error sending response to client "+err.Error())
227 }
228 return nil
229}
230
231//GetHWComponentInfo gets the details of a particular HW component
232func (dms *DmiAPIServer) GetHWComponentInfo(req *dmi.HWComponentInfoGetRequest, stream dmi.NativeHWManagementService_GetHWComponentInfoServer) error {
233 logger.Debugf("GetHWComponentInfo() invoked with request %+v", req)
234
235 if req == nil {
236 return status.Errorf(codes.FailedPrecondition, "can not entertain nil request")
237 }
238 if stream == nil {
239 logger.Errorf("stream to send is nil, not sending response from gRPC server ")
240 return status.Errorf(codes.Internal, "stream to send is nil, can not send response from gRPC server")
241 }
242
243 componentFound := Contains(dms.ponTransceiverUuids, req.ComponentUuid.Uuid)
244 if !componentFound {
245 componentFound = Contains(dms.ponTransceiverCageUuids, req.ComponentUuid.Uuid)
246 }
247
248 if req.DeviceUuid.Uuid != dms.uuid || !componentFound {
249 // Wrong uuid, return error
250 return sendGetHWComponentResponse(nil, stream)
251 }
252
253 // Search for the component and return it
254 c := findComponent(dms.components, req.ComponentUuid.Uuid)
255 return sendGetHWComponentResponse(c, stream)
256}
257
258//SetHWComponentInfo sets the permissible attributes of a HW component
259func (dms *DmiAPIServer) SetHWComponentInfo(context.Context, *dmi.HWComponentInfoSetRequest) (*dmi.HWComponentInfoSetResponse, error) {
260 return nil, status.Errorf(codes.Unimplemented, "rpc SetHWComponentInfo not implemented")
261}
262
263//SetLoggingEndpoint sets the location to which logs need to be shipped
264func (dms *DmiAPIServer) SetLoggingEndpoint(context.Context, *dmi.SetLoggingEndpointRequest) (*dmi.SetRemoteEndpointResponse, error) {
265 return nil, status.Errorf(codes.Unimplemented, "rpc SetLoggingEndpoint not implemented")
266}
267
268//GetLoggingEndpoint gets the configured location to which the logs are being shipped
269func (dms *DmiAPIServer) GetLoggingEndpoint(context.Context, *dmi.Uuid) (*dmi.GetLoggingEndpointResponse, error) {
270 return nil, status.Errorf(codes.Unimplemented, "rpc GetLoggingEndpoint not implemented")
271}
272
273//SetMsgBusEndpoint sets the location of the Message Bus to which events and metrics are shipped
274func (dms *DmiAPIServer) SetMsgBusEndpoint(context.Context, *dmi.SetMsgBusEndpointRequest) (*dmi.SetRemoteEndpointResponse, error) {
275 return nil, status.Errorf(codes.Unimplemented, "rpc SetMsgBusEndpoint not implemented")
276}
277
278//GetMsgBusEndpoint gets the configured location to which the events and metrics are being shipped
279func (dms *DmiAPIServer) GetMsgBusEndpoint(context.Context, *empty.Empty) (*dmi.GetMsgBusEndpointResponse, error) {
280 return nil, status.Errorf(codes.Unimplemented, "rpc GetMsgBusEndpoint not implemented")
281}
282
283//GetManagedDevices returns an object containing a list of devices managed by this entity
284func (dms *DmiAPIServer) GetManagedDevices(context.Context, *empty.Empty) (*dmi.ManagedDevicesResponse, error) {
285 retResponse := dmi.ManagedDevicesResponse{}
286 //If our uuid is empty, we return empty list; else we fill details and return
287 if dms.uuid != "" {
288 root := dmi.ModifiableComponent{
289 Name: dms.deviceName,
290 Uri: &dmi.Uri{
291 Uri: dms.ipAddress,
292 },
293 }
294
295 retResponse.Devices = append(retResponse.Devices, &root)
296 }
297
298 return &retResponse, nil
299}