Prince Pereira | c1c21d6 | 2021-04-22 08:38:15 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2020-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 | |
| 17 | // Package modifiablecomponent stores ModifiableComponent methods and functions |
| 18 | package device |
| 19 | |
| 20 | import ( |
| 21 | "context" |
| 22 | "encoding/json" |
| 23 | "errors" |
| 24 | "fmt" |
| 25 | |
| 26 | "github.com/opencord/device-management-interface/go/dmi" |
| 27 | |
| 28 | "github.com/opencord/voltha-lib-go/v4/pkg/log" |
| 29 | |
| 30 | "github.com/opencord/opendevice-manager/pkg/db" |
| 31 | |
| 32 | copy "github.com/jinzhu/copier" |
| 33 | ) |
| 34 | |
| 35 | // DBGetByName func reads device record by name |
| 36 | func DBGetByName(ctx context.Context, name string) (*DeviceRecord, error) { |
| 37 | if name == "" { |
| 38 | logger.Errorw(ctx, "DBGetByName-failed-missing-device-name", log.Fields{}) |
| 39 | return nil, errors.New("name field is empty") |
| 40 | } |
| 41 | |
| 42 | logger.Debugw(ctx, "DBGetByName-invoked", log.Fields{"name": name}) |
| 43 | defer logger.Debugw(ctx, "DBGetByName-completed", log.Fields{"name": name}) |
| 44 | |
| 45 | if val, ok := cache.nameToRec.Load(name); ok { |
| 46 | return val.(*DeviceRecord), nil |
| 47 | } |
| 48 | |
| 49 | key := fmt.Sprintf(DbPathNameToRecord, name) |
| 50 | entry, err := db.Read(ctx, key) |
| 51 | if err != nil { |
| 52 | logger.Errorw(ctx, "DBGetByName-failed-read-db", log.Fields{"error": err, "key": key}) |
| 53 | return nil, err |
| 54 | } |
| 55 | |
| 56 | rec := new(DeviceRecord) |
| 57 | if err = json.Unmarshal([]byte(entry), rec); err != nil { |
| 58 | logger.Errorw(ctx, "Failed-to-unmarshal-at-DBGetByName", log.Fields{"reason": err, "entry": entry}) |
| 59 | return nil, err |
| 60 | } |
| 61 | |
| 62 | cache.nameToRec.Store(name, rec) |
| 63 | |
| 64 | return rec, nil |
| 65 | } |
| 66 | |
| 67 | // DBGetByUuid func reads device record by Uuid |
| 68 | func DBGetByUuid(ctx context.Context, uuid string) (*DeviceRecord, error) { |
| 69 | |
| 70 | if uuid == "" { |
| 71 | logger.Errorw(ctx, "DBGetByUuid-failed-missing-device-uuid", log.Fields{}) |
| 72 | return nil, errors.New("uuid field is empty") |
| 73 | } |
| 74 | |
| 75 | logger.Debugw(ctx, "DBGetByUuid-invoked", log.Fields{"uuid": uuid}) |
| 76 | defer logger.Debugw(ctx, "DBGetByUuid-completed", log.Fields{"uuid": uuid}) |
| 77 | |
| 78 | var name string |
| 79 | var err error |
| 80 | |
| 81 | if val, ok := cache.uuidToName.Load(uuid); ok { |
| 82 | name = val.(string) |
| 83 | } else { |
| 84 | |
| 85 | key := fmt.Sprintf(DbPathUuidToName, uuid) |
| 86 | name, err = db.Read(ctx, key) |
| 87 | if err != nil { |
| 88 | logger.Errorw(ctx, "DBGetByUuid-failed-read-db", log.Fields{"error": err, "key": key}) |
| 89 | return nil, err |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | cache.uuidToName.Store(uuid, name) |
| 94 | |
| 95 | return DBGetByName(ctx, name) |
| 96 | } |
| 97 | |
| 98 | // DBGetAll func returns all device records |
| 99 | func DBGetAll(ctx context.Context) ([]*DeviceRecord, error) { |
| 100 | key := fmt.Sprintf(DbPathNameToRecord, "") |
| 101 | kvPairs, err := db.ReadAll(ctx, key) |
| 102 | if err != nil { |
| 103 | logger.Errorw(ctx, "DBGetAll-failed-read-db", log.Fields{"error": err, "key": key}) |
| 104 | return nil, err |
| 105 | } |
| 106 | |
| 107 | var listDevs []*DeviceRecord |
| 108 | |
| 109 | for _, entry := range kvPairs { |
| 110 | rec := new(DeviceRecord) |
| 111 | if err = json.Unmarshal([]byte(entry), rec); err != nil { |
| 112 | logger.Errorw(ctx, "Failed-to-unmarshal-at-DBGetByName", log.Fields{"reason": err, "entry": entry}) |
| 113 | } else { |
| 114 | listDevs = append(listDevs, rec) |
| 115 | } |
| 116 | } |
| 117 | |
| 118 | logger.Infow(ctx, "DBGetAll-success", log.Fields{"entry": listDevs}) |
| 119 | |
| 120 | return listDevs, nil |
| 121 | } |
| 122 | |
| 123 | // DBAddByName inserts Device Info record to DB with Name as Key |
| 124 | func (rec *DeviceRecord) DBAddByName(ctx context.Context) error { |
| 125 | if rec.Name == "" { |
| 126 | logger.Errorw(ctx, "DBAddByName-failed-missing-device-name", log.Fields{"rec": rec}) |
| 127 | return errors.New("missing name") |
| 128 | } |
| 129 | key := fmt.Sprintf(DbPathNameToRecord, rec.Name) |
| 130 | b, _ := json.Marshal(rec) |
| 131 | entry := string(b) |
| 132 | err := db.Put(ctx, key, entry) |
| 133 | cache.nameToRec.Store(rec.Name, rec) |
| 134 | logger.Infow(ctx, "Inserting-device-info-to-Db-in-DBAddByName-method", log.Fields{"rec": rec, "error": err}) |
| 135 | return err |
| 136 | } |
| 137 | |
| 138 | // DBAddUuidLookup creates a lookup of name from uuid |
| 139 | func (rec *DeviceRecord) DBAddUuidLookup(ctx context.Context) error { |
| 140 | if rec.Uuid == "" || rec.Name == "" { |
| 141 | logger.Errorw(ctx, "DBAddUuidLookup-failed-missing-device-name-or-uuid", log.Fields{"rec": rec}) |
| 142 | return errors.New("missing name") |
| 143 | } |
| 144 | key := fmt.Sprintf(DbPathUuidToName, rec.Uuid) |
| 145 | err := db.Put(ctx, key, rec.Name) |
| 146 | cache.uuidToName.Store(rec.Uuid, rec.Name) |
| 147 | logger.Infow(ctx, "DBAddUuidLookup-success", log.Fields{"rec": rec, "error": err}) |
| 148 | return err |
| 149 | } |
| 150 | |
| 151 | // DBDelRecord deletes all entries for Device Info |
| 152 | func (rec *DeviceRecord) DBDelRecord(ctx context.Context) error { |
| 153 | |
| 154 | var err error |
| 155 | |
| 156 | if rec.Name != "" { |
| 157 | key := fmt.Sprintf(DbPathNameToRecord, rec.Name) |
| 158 | logger.Infow(ctx, "deleting-device-info-record-using-name", log.Fields{"name": rec.Name, "key": key}) |
| 159 | err = db.Del(ctx, key) |
| 160 | cache.nameToRec.Delete(rec.Name) |
| 161 | } |
| 162 | |
| 163 | if err == nil && rec.Uuid != "" { |
| 164 | key := fmt.Sprintf(DbPathUuidToName, rec.Uuid) |
| 165 | logger.Infow(ctx, "deleting-device-info-record-using-uuid", log.Fields{"uuid": rec.Uuid, "key": key}) |
| 166 | err = db.Del(ctx, key) |
| 167 | cache.uuidToName.Delete(rec.Uuid) |
| 168 | } |
| 169 | |
| 170 | return err |
| 171 | } |
| 172 | |
| 173 | // DBSaveHwInfo stores hardware copies info from response and stores in db |
| 174 | func (rec *DeviceRecord) DBSaveHwInfo(ctx context.Context, hw *dmi.Hardware) error { |
| 175 | defer logger.Infow(ctx, "saving-hw-info-to-device-record-completed", log.Fields{"rec": rec}) |
| 176 | rec.LastBooted = hw.LastBooted |
| 177 | rec.LastChange = hw.LastChange |
| 178 | name := rec.Name |
| 179 | uuid := rec.Uuid |
| 180 | if err := copy.Copy(&rec, &hw.Root); err != nil { |
| 181 | logger.Errorw(ctx, "copy-failed-at-DBSaveHwInfo", log.Fields{"rec": rec, "error": err, "hw": hw}) |
| 182 | return err |
| 183 | } |
| 184 | rec.Children = []string{} |
| 185 | for _, child := range hw.Root.Children { |
| 186 | rec.Children = append(rec.Children, child.Uuid.Uuid) |
| 187 | } |
| 188 | rec.Name = name |
| 189 | rec.Uuid = uuid |
| 190 | return rec.DBAddByName(ctx) |
| 191 | } |