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