mpagenko | c8bba41 | 2021-01-15 15:38:44 +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 adaptercoreonu provides the utility for onu devices, flows and statistics |
| 18 | package adaptercoreonu |
| 19 | |
| 20 | import ( |
mpagenko | 80622a5 | 2021-02-09 16:53:23 +0000 | [diff] [blame] | 21 | "bufio" |
mpagenko | c8bba41 | 2021-01-15 15:38:44 +0000 | [diff] [blame] | 22 | "context" |
mpagenko | 15ff4a5 | 2021-03-02 10:09:20 +0000 | [diff] [blame^] | 23 | "errors" |
mpagenko | 80622a5 | 2021-02-09 16:53:23 +0000 | [diff] [blame] | 24 | "os" |
mpagenko | c8bba41 | 2021-01-15 15:38:44 +0000 | [diff] [blame] | 25 | "sync" |
| 26 | |
| 27 | //"time" |
| 28 | |
| 29 | "github.com/opencord/voltha-protos/v4/go/voltha" |
| 30 | |
| 31 | "github.com/opencord/voltha-lib-go/v4/pkg/log" |
| 32 | ) |
| 33 | |
| 34 | // ### downloadToAdapter related definitions #### |
| 35 | |
| 36 | //not yet defined to go with sca..., later also some configure options ?? |
| 37 | //const defaultDownloadTimeout = 60 // (?) Seconds |
| 38 | //const localImgPath = "/home/lcui/work/tmp" |
| 39 | |
| 40 | // ### downloadToAdapter - end #### |
| 41 | |
| 42 | //adapterDownloadManager structure holds information needed for downloading to and storing images within the adapter |
| 43 | type adapterDownloadManager struct { |
| 44 | mutexDownloadImageDsc sync.RWMutex |
| 45 | downloadImageDscSlice []*voltha.ImageDownload |
mpagenko | 80622a5 | 2021-02-09 16:53:23 +0000 | [diff] [blame] | 46 | // maybe just for test purpose |
| 47 | arrayFileFragment [32]byte |
mpagenko | c8bba41 | 2021-01-15 15:38:44 +0000 | [diff] [blame] | 48 | } |
| 49 | |
| 50 | //newAdapterDownloadManager constructor returns a new instance of a adapterDownloadManager |
| 51 | //mib_db (as well as not inluded alarm_db not really used in this code? VERIFY!!) |
| 52 | func newAdapterDownloadManager(ctx context.Context) *adapterDownloadManager { |
| 53 | logger.Debug(ctx, "init-adapterDownloadManager") |
| 54 | var localDnldMgr adapterDownloadManager |
| 55 | localDnldMgr.downloadImageDscSlice = make([]*voltha.ImageDownload, 0) |
mpagenko | c8bba41 | 2021-01-15 15:38:44 +0000 | [diff] [blame] | 56 | return &localDnldMgr |
| 57 | } |
| 58 | |
| 59 | //imageExists returns true if the requested image already exists within the adapter |
| 60 | func (dm *adapterDownloadManager) imageExists(ctx context.Context, apImageDsc *voltha.ImageDownload) bool { |
| 61 | logger.Debugw(ctx, "checking on existence of the image", log.Fields{"image-name": (*apImageDsc).Name}) |
| 62 | dm.mutexDownloadImageDsc.RLock() |
| 63 | defer dm.mutexDownloadImageDsc.RUnlock() |
| 64 | |
| 65 | for _, pDnldImgDsc := range dm.downloadImageDscSlice { |
| 66 | if (*pDnldImgDsc).Name == (*apImageDsc).Name { |
| 67 | //image found (by name) |
| 68 | return true |
| 69 | } |
| 70 | } |
| 71 | //image not found (by name) |
| 72 | return false |
| 73 | } |
| 74 | |
mpagenko | 80622a5 | 2021-02-09 16:53:23 +0000 | [diff] [blame] | 75 | //imageLocallyDownloaded returns true if the requested image already exists within the adapter |
| 76 | func (dm *adapterDownloadManager) imageLocallyDownloaded(ctx context.Context, apImageDsc *voltha.ImageDownload) bool { |
| 77 | logger.Debugw(ctx, "checking if image is fully downloaded", log.Fields{"image-name": (*apImageDsc).Name}) |
| 78 | dm.mutexDownloadImageDsc.RLock() |
| 79 | defer dm.mutexDownloadImageDsc.RUnlock() |
| 80 | |
| 81 | for _, pDnldImgDsc := range dm.downloadImageDscSlice { |
| 82 | if (*pDnldImgDsc).Name == (*apImageDsc).Name { |
| 83 | //image found (by name) |
| 84 | if (*pDnldImgDsc).DownloadState == voltha.ImageDownload_DOWNLOAD_SUCCEEDED { |
| 85 | logger.Debugw(ctx, "image has been fully downloaded", log.Fields{"image-name": (*apImageDsc).Name}) |
| 86 | return true |
| 87 | } |
| 88 | logger.Debugw(ctx, "image not yet fully downloaded", log.Fields{"image-name": (*apImageDsc).Name}) |
| 89 | return false |
| 90 | } |
| 91 | } |
| 92 | //image not found (by name) |
| 93 | logger.Errorw(ctx, "image does not exist", log.Fields{"image-name": (*apImageDsc).Name}) |
| 94 | return false |
| 95 | } |
| 96 | |
mpagenko | c8bba41 | 2021-01-15 15:38:44 +0000 | [diff] [blame] | 97 | //startDownload returns true if the download of the requested image could be started |
| 98 | func (dm *adapterDownloadManager) startDownload(ctx context.Context, apImageDsc *voltha.ImageDownload) error { |
mpagenko | 15ff4a5 | 2021-03-02 10:09:20 +0000 | [diff] [blame^] | 99 | if apImageDsc.LocalDir != "" { |
| 100 | logger.Infow(ctx, "image download-to-adapter requested", log.Fields{"image-name": apImageDsc.Name}) |
| 101 | newImageDscPos := len(dm.downloadImageDscSlice) |
| 102 | dm.downloadImageDscSlice = append(dm.downloadImageDscSlice, apImageDsc) |
| 103 | dm.downloadImageDscSlice[newImageDscPos].DownloadState = voltha.ImageDownload_DOWNLOAD_STARTED |
| 104 | //just some basic test file simulation |
| 105 | go dm.writeFileToLFS(ctx, apImageDsc.Name, apImageDsc.LocalDir) |
| 106 | //return success to comfort the core processing during integration |
| 107 | return nil |
| 108 | } |
| 109 | // we can use the missing local path temporary also to test some failure behavior (system reation on failure) |
| 110 | // with updated control API's or at some adequate time we could also set some defined fixed localPath internally |
| 111 | logger.Errorw(ctx, "could not start download: no valid local directory to write to", log.Fields{"image-name": (*apImageDsc).Name}) |
| 112 | return errors.New("could not start download: no valid local directory to write to") |
mpagenko | c8bba41 | 2021-01-15 15:38:44 +0000 | [diff] [blame] | 113 | } |
mpagenko | 80622a5 | 2021-02-09 16:53:23 +0000 | [diff] [blame] | 114 | |
| 115 | //writeFileToLFS writes the downloaded file to the local file system |
| 116 | func (dm *adapterDownloadManager) writeFileToLFS(ctx context.Context, aFileName string, aLocalPath string) { |
| 117 | // by now just a simulation to write a file with predefined 'variable' content |
| 118 | totalFileLength := 0 |
mpagenko | 15ff4a5 | 2021-03-02 10:09:20 +0000 | [diff] [blame^] | 119 | logger.Debugw(ctx, "writing fixed size simulation file locally", log.Fields{ |
mpagenko | 80622a5 | 2021-02-09 16:53:23 +0000 | [diff] [blame] | 120 | "image-name": aFileName, "image-path": aLocalPath}) |
| 121 | file, err := os.Create(aLocalPath + "/" + aFileName) |
| 122 | if err == nil { |
| 123 | // write 32KB test file |
| 124 | for totalFileLength < 32*1024 { |
| 125 | if written, wrErr := file.Write(dm.getIncrementalSliceContent(ctx)); wrErr == nil { |
| 126 | totalFileLength += written |
| 127 | } else { |
mpagenko | 15ff4a5 | 2021-03-02 10:09:20 +0000 | [diff] [blame^] | 128 | logger.Errorw(ctx, "could not write to file", log.Fields{"create-error": wrErr}) |
mpagenko | 80622a5 | 2021-02-09 16:53:23 +0000 | [diff] [blame] | 129 | break //stop writing |
| 130 | } |
| 131 | } |
| 132 | } else { |
mpagenko | 15ff4a5 | 2021-03-02 10:09:20 +0000 | [diff] [blame^] | 133 | logger.Errorw(ctx, "could not create file", log.Fields{"create-error": err}) |
mpagenko | 80622a5 | 2021-02-09 16:53:23 +0000 | [diff] [blame] | 134 | } |
| 135 | |
| 136 | fileStats, statsErr := file.Stat() |
| 137 | if err != nil { |
| 138 | logger.Errorw(ctx, "created file can't be accessed", log.Fields{"stat-error": statsErr}) |
| 139 | } |
mpagenko | 15ff4a5 | 2021-03-02 10:09:20 +0000 | [diff] [blame^] | 140 | logger.Infow(ctx, "written file size is", log.Fields{"file": aLocalPath + "/" + aFileName, "length": fileStats.Size()}) |
mpagenko | 80622a5 | 2021-02-09 16:53:23 +0000 | [diff] [blame] | 141 | //nolint:gosec,errcheck |
| 142 | file.Close() |
| 143 | |
| 144 | for _, pDnldImgDsc := range dm.downloadImageDscSlice { |
| 145 | if (*pDnldImgDsc).Name == aFileName { |
| 146 | //image found (by name) |
| 147 | (*pDnldImgDsc).DownloadState = voltha.ImageDownload_DOWNLOAD_SUCCEEDED |
| 148 | return //can leave directly |
| 149 | } |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | //getImageBufferLen returns the length of the specified file in bytes (file size) |
| 154 | func (dm *adapterDownloadManager) getImageBufferLen(ctx context.Context, aFileName string, |
| 155 | aLocalPath string) (int64, error) { |
| 156 | //maybe we can also use FileSize from dm.downloadImageDscSlice - future option? |
| 157 | |
| 158 | //nolint:gosec |
| 159 | file, err := os.Open(aLocalPath + "/" + aFileName) |
| 160 | if err != nil { |
| 161 | return 0, err |
| 162 | } |
| 163 | //nolint:errcheck |
| 164 | defer file.Close() |
| 165 | |
| 166 | stats, statsErr := file.Stat() |
| 167 | if statsErr != nil { |
| 168 | return 0, statsErr |
| 169 | } |
| 170 | |
| 171 | return stats.Size(), nil |
| 172 | } |
| 173 | |
| 174 | //getDownloadImageBuffer returns the content of the requested file as byte slice |
| 175 | func (dm *adapterDownloadManager) getDownloadImageBuffer(ctx context.Context, aFileName string, |
| 176 | aLocalPath string) ([]byte, error) { |
| 177 | //nolint:gosec |
| 178 | file, err := os.Open(aLocalPath + "/" + aFileName) |
| 179 | if err != nil { |
| 180 | return nil, err |
| 181 | } |
| 182 | //nolint:errcheck |
| 183 | defer file.Close() |
| 184 | |
| 185 | stats, statsErr := file.Stat() |
| 186 | if statsErr != nil { |
| 187 | return nil, statsErr |
| 188 | } |
| 189 | |
| 190 | var size int64 = stats.Size() |
| 191 | bytes := make([]byte, size) |
| 192 | |
| 193 | buffer := bufio.NewReader(file) |
| 194 | _, err = buffer.Read(bytes) |
| 195 | |
| 196 | return bytes, err |
| 197 | } |
| 198 | |
| 199 | //getIncrementalSliceContent returns a byte slice of incremented bytes of internal array (used for file emulation) |
| 200 | // (used for file emulation) |
| 201 | func (dm *adapterDownloadManager) getIncrementalSliceContent(ctx context.Context) []byte { |
| 202 | lastValue := dm.arrayFileFragment[len(dm.arrayFileFragment)-1] |
| 203 | for index := range dm.arrayFileFragment { |
| 204 | lastValue++ |
| 205 | dm.arrayFileFragment[index] = lastValue |
| 206 | } |
| 207 | return dm.arrayFileFragment[:] |
| 208 | } |