VOL-3052 Onu Software upgrade addendum: omci-lib-go update + download robustness
Signed-off-by: mpagenko <michael.pagenkopf@adtran.com>
Change-Id: I80f888f074e9a0ee82cd8f7b69404994e77885b1
diff --git a/internal/pkg/onuadaptercore/adapter_download_manager.go b/internal/pkg/onuadaptercore/adapter_download_manager.go
index a49698f..e30d329 100644
--- a/internal/pkg/onuadaptercore/adapter_download_manager.go
+++ b/internal/pkg/onuadaptercore/adapter_download_manager.go
@@ -21,6 +21,7 @@
"bufio"
"context"
"errors"
+ "fmt"
"io"
"net/http"
"net/url"
@@ -115,7 +116,10 @@
}
//try to download from http
urlName := apImageDsc.Url + "/" + apImageDsc.Name
- go dm.downloadFile(ctx, urlName, apImageDsc.LocalDir, apImageDsc.Name)
+ err := dm.downloadFile(ctx, urlName, apImageDsc.LocalDir, apImageDsc.Name)
+ if err != nil {
+ return (err)
+ }
//return success to comfort the core processing during integration
return nil
}
@@ -126,71 +130,105 @@
}
//downloadFile downloads the specified file from the given http location
-func (dm *adapterDownloadManager) downloadFile(ctx context.Context, aURLName string, aFilePath string, aFileName string) {
+func (dm *adapterDownloadManager) downloadFile(ctx context.Context, aURLName string, aFilePath string, aFileName string) error {
// Get the data
logger.Infow(ctx, "downloading from http", log.Fields{"url": aURLName, "localPath": aFilePath})
// http command is already part of the aURLName argument
urlBase, err1 := url.Parse(aURLName)
if err1 != nil {
logger.Errorw(ctx, "could not set base url command", log.Fields{"url": aURLName, "error": err1})
+ return fmt.Errorf("could not set base url command: %s, error: %s", aURLName, err1)
}
urlParams := url.Values{}
urlBase.RawQuery = urlParams.Encode()
- req, err2 := http.NewRequest("GET", urlBase.String(), nil)
- if err2 != nil {
- logger.Errorw(ctx, "could not generate http request", log.Fields{"url": urlBase.String(), "error": err2})
- return
- }
- ctx, cancel := context.WithDeadline(ctx, time.Now().Add(10*time.Second)) //timeout to be discussed
- defer cancel()
- _ = req.WithContext(ctx)
- resp, err3 := http.DefaultClient.Do(req)
- if err3 != nil {
- logger.Errorw(ctx, "could not http get from url", log.Fields{"url": urlBase.String(), "error": err3})
- return
+ //pre-check on file existence
+ reqExist, errExist2 := http.NewRequest("HEAD", urlBase.String(), nil)
+ if errExist2 != nil {
+ logger.Errorw(ctx, "could not generate http head request", log.Fields{"url": urlBase.String(), "error": errExist2})
+ return fmt.Errorf("could not generate http head request: %s, error: %s", aURLName, errExist2)
+ }
+ ctxExist, cancelExist := context.WithDeadline(ctx, time.Now().Add(3*time.Second)) //waiting for some fast answer
+ defer cancelExist()
+ _ = reqExist.WithContext(ctxExist)
+ respExist, errExist3 := http.DefaultClient.Do(reqExist)
+ if errExist3 != nil || respExist.StatusCode != http.StatusOK {
+ logger.Infow(ctx, "could not http head from url", log.Fields{"url": urlBase.String(),
+ "error": errExist3, "status": respExist.StatusCode})
+ //if head is not supported by server we cannot use this test and just try to continue
+ if respExist.StatusCode != http.StatusMethodNotAllowed {
+ logger.Errorw(ctx, "http head from url: file does not exist here, aborting", log.Fields{"url": urlBase.String(),
+ "error": errExist3, "status": respExist.StatusCode})
+ return fmt.Errorf("http head from url: file does not exist here, aborting: %s, error: %s, status: %d",
+ aURLName, errExist2, respExist.StatusCode)
+ }
}
defer func() {
- deferredErr := resp.Body.Close()
+ deferredErr := respExist.Body.Close()
if deferredErr != nil {
- logger.Errorw(ctx, "error at closing http response body", log.Fields{"url": urlBase.String(), "error": deferredErr})
+ logger.Errorw(ctx, "error at closing http head response body", log.Fields{"url": urlBase.String(), "error": deferredErr})
}
}()
- // Create the file
- aLocalPathName := aFilePath + "/" + aFileName
- file, err := os.Create(aLocalPathName)
- if err != nil {
- logger.Errorw(ctx, "could not create local file", log.Fields{"path_file": aLocalPathName, "error": err})
- return
- }
- defer func() {
- deferredErr := file.Close()
- if deferredErr != nil {
- logger.Errorw(ctx, "error at closing new file", log.Fields{"path_file": aLocalPathName, "error": deferredErr})
+ //trying to download - do it in background as it may take some time ...
+ go func() {
+ req, err2 := http.NewRequest("GET", urlBase.String(), nil)
+ if err2 != nil {
+ logger.Errorw(ctx, "could not generate http request", log.Fields{"url": urlBase.String(), "error": err2})
+ return
+ }
+ ctx, cancel := context.WithDeadline(ctx, time.Now().Add(10*time.Second)) //long timeout for remote server and big file
+ defer cancel()
+ _ = req.WithContext(ctx)
+ resp, err3 := http.DefaultClient.Do(req)
+ if err3 != nil || respExist.StatusCode != http.StatusOK {
+ logger.Errorw(ctx, "could not http get from url", log.Fields{"url": urlBase.String(),
+ "error": err3, "status": respExist.StatusCode})
+ return
+ }
+ defer func() {
+ deferredErr := resp.Body.Close()
+ if deferredErr != nil {
+ logger.Errorw(ctx, "error at closing http get response body", log.Fields{"url": urlBase.String(), "error": deferredErr})
+ }
+ }()
+
+ // Create the file
+ aLocalPathName := aFilePath + "/" + aFileName
+ file, err := os.Create(aLocalPathName)
+ if err != nil {
+ logger.Errorw(ctx, "could not create local file", log.Fields{"path_file": aLocalPathName, "error": err})
+ return
+ }
+ defer func() {
+ deferredErr := file.Close()
+ if deferredErr != nil {
+ logger.Errorw(ctx, "error at closing new file", log.Fields{"path_file": aLocalPathName, "error": deferredErr})
+ }
+ }()
+
+ // Write the body to file
+ _, err = io.Copy(file, resp.Body)
+ if err != nil {
+ logger.Errorw(ctx, "could not copy file content", log.Fields{"url": urlBase.String(), "file": aLocalPathName, "error": err})
+ return
+ }
+
+ fileStats, statsErr := file.Stat()
+ if err != nil {
+ logger.Errorw(ctx, "created file can't be accessed", log.Fields{"file": aLocalPathName, "stat-error": statsErr})
+ }
+ logger.Infow(ctx, "written file size is", log.Fields{"file": aLocalPathName, "length": fileStats.Size()})
+
+ for _, pDnldImgDsc := range dm.downloadImageDscSlice {
+ if (*pDnldImgDsc).Name == aFileName {
+ //image found (by name)
+ (*pDnldImgDsc).DownloadState = voltha.ImageDownload_DOWNLOAD_SUCCEEDED
+ return //can leave directly
+ }
}
}()
-
- // Write the body to file
- _, err = io.Copy(file, resp.Body)
- if err != nil {
- logger.Errorw(ctx, "could not copy file content", log.Fields{"url": urlBase.String(), "file": aLocalPathName, "error": err})
- return
- }
-
- fileStats, statsErr := file.Stat()
- if err != nil {
- logger.Errorw(ctx, "created file can't be accessed", log.Fields{"file": aLocalPathName, "stat-error": statsErr})
- }
- logger.Infow(ctx, "written file size is", log.Fields{"file": aLocalPathName, "length": fileStats.Size()})
-
- for _, pDnldImgDsc := range dm.downloadImageDscSlice {
- if (*pDnldImgDsc).Name == aFileName {
- //image found (by name)
- (*pDnldImgDsc).DownloadState = voltha.ImageDownload_DOWNLOAD_SUCCEEDED
- return //can leave directly
- }
- }
+ return nil
}
//writeFileToLFS writes the downloaded file to the local file system