From ed1eb7309133a9090837e86ff3ee0b6e0eaef28c Mon Sep 17 00:00:00 2001 From: Mehant Kammakomati Date: Sun, 2 Jul 2023 19:28:20 +0530 Subject: [PATCH] feat: input config files from http links (#1056) Signed-off-by: Mehant Kammakomati --- cmd/plan.go | 9 ++-- cmd/transform.go | 9 ++-- common/download/download.go | 56 ++++++++++++++++++++++++ common/download/httpdownload.go | 76 +++++++++++++++++++++++++++++++++ common/utils.go | 9 ++++ qaengine/engine.go | 9 ++++ 6 files changed, 162 insertions(+), 6 deletions(-) create mode 100644 common/download/download.go create mode 100644 common/download/httpdownload.go diff --git a/cmd/plan.go b/cmd/plan.go index 4f6799190..f7eea7920 100644 --- a/cmd/plan.go +++ b/cmd/plan.go @@ -25,6 +25,7 @@ import ( "strings" "github.com/konveyor/move2kube/common" + "github.com/konveyor/move2kube/common/download" "github.com/konveyor/move2kube/common/vcs" "github.com/konveyor/move2kube/lib" "github.com/konveyor/move2kube/qaengine" @@ -90,10 +91,12 @@ func planHandler(cmd *cobra.Command, flags planFlags) { } // make all path(s) absolute for i, c := range flags.configs { - if c, err := filepath.Abs(c); err != nil { - logrus.Fatalf("failed to make the config file path %s absolute. Error: %q", c, err) + if !download.IsRemotePath(c) { + if c, err := filepath.Abs(c); err != nil { + logrus.Fatalf("failed to make the config file path %s absolute. Error: %q", c, err) + } + flags.configs[i] = c } - flags.configs[i] = c } customizationsPath := flags.customizationsPath diff --git a/cmd/transform.go b/cmd/transform.go index c70bab1d8..2e8148458 100644 --- a/cmd/transform.go +++ b/cmd/transform.go @@ -23,6 +23,7 @@ import ( "path/filepath" "github.com/konveyor/move2kube/common" + "github.com/konveyor/move2kube/common/download" "github.com/konveyor/move2kube/common/vcs" "github.com/konveyor/move2kube/lib" "github.com/konveyor/move2kube/types/plan" @@ -104,10 +105,12 @@ func transformHandler(cmd *cobra.Command, flags transformFlags) { } // make all path(s) absolute for i, c := range flags.configs { - if c, err := filepath.Abs(c); err != nil { - logrus.Fatalf("failed to make the config file path %s absolute. Error: %q", c, err) + if !download.IsRemotePath(c) { + if c, err := filepath.Abs(c); err != nil { + logrus.Fatalf("failed to make the config file path %s absolute. Error: %q", c, err) + } + flags.configs[i] = c } - flags.configs[i] = c } // Global settings diff --git a/common/download/download.go b/common/download/download.go new file mode 100644 index 000000000..545405e7e --- /dev/null +++ b/common/download/download.go @@ -0,0 +1,56 @@ +/* + * Copyright IBM Corporation 2023 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package download + +import ( + "github.com/konveyor/move2kube/common" + "github.com/sirupsen/logrus" +) + +// DownloadOptions stores options for the downloader +type DownloadOptions struct { + ContentURL string + DownloadDestinationPath string + Overwrite bool +} + +// Downloader defines interface for downloaders +type Downloader interface { + Download(DownloadOptions) (string, error) +} + +// IsRemotePath checks if the provided string is a valid remote path or not +func IsRemotePath(str string) bool { + return common.IsHTTPURL(str) +} + +// GetDownloadedPath downloads the content using suitable downloader and then returns the downloaded file path +func GetDownloadedPath(contentURL string, downloadDestinationPath string, overwrite bool) string { + var err error + downloadedPath := "" + if common.IsHTTPURL(contentURL) { + content := HTTPContent{} + downloadOpts := DownloadOptions{ContentURL: contentURL, DownloadDestinationPath: downloadDestinationPath, Overwrite: overwrite} + downloadedPath, err = content.Download(downloadOpts) + if err != nil { + logrus.Fatalf("failed to download the content using http downloader. Error : %+v", err) + } + } else { + logrus.Fatalf("other downloader backends are not currently supported.") + } + return downloadedPath +} diff --git a/common/download/httpdownload.go b/common/download/httpdownload.go new file mode 100644 index 000000000..ca7e02ad9 --- /dev/null +++ b/common/download/httpdownload.go @@ -0,0 +1,76 @@ +/* + * Copyright IBM Corporation 2023 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package download + +import ( + "fmt" + "io" + "net/http" + "os" + + "github.com/sirupsen/logrus" +) + +// HTTPContent stores remote content config +type HTTPContent struct { + ContentFilePath string +} + +// Download downloads content from the given content URL +func (content *HTTPContent) Download(downloadOptions DownloadOptions) (string, error) { + if downloadOptions.DownloadDestinationPath == "" { + return "", fmt.Errorf("the path where the content has to be downloaded is empty - %s", downloadOptions.DownloadDestinationPath) + } + + _, err := os.Stat(downloadOptions.DownloadDestinationPath) + if os.IsNotExist(err) { + logrus.Debugf("downloaded content would be available at '%s'", downloadOptions.DownloadDestinationPath) + } else if downloadOptions.Overwrite { + logrus.Infof("downloaded content will be overwritten at %s", downloadOptions.DownloadDestinationPath) + err = os.RemoveAll(downloadOptions.DownloadDestinationPath) + if err != nil { + return "", fmt.Errorf("failed to remove the directory at the given path - %s. Error : %+v", downloadOptions.DownloadDestinationPath, err) + } + } else { + return downloadOptions.DownloadDestinationPath, nil + } + logrus.Infof("Downloading the content using http downloader into %s. This might take some time.", downloadOptions.DownloadDestinationPath) + + out, err := os.Create(downloadOptions.DownloadDestinationPath) + if err != nil { + return "", fmt.Errorf("failed to create a file for the provided path - %s. Error : %+v", downloadOptions.DownloadDestinationPath, err) + } + defer out.Close() + + resp, err := http.Get(downloadOptions.ContentURL) + if err != nil { + return "", fmt.Errorf("failed to http get content from the provided content url - %s. Error : %+v", downloadOptions.ContentURL, err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("failed to http get content from the provided content url - %s. Received status code %d", downloadOptions.ContentURL, resp.StatusCode) + } + + _, err = io.Copy(out, resp.Body) + if err != nil { + return "", fmt.Errorf("failed to copy content from response to file. Error : %+v", err) + } + content.ContentFilePath = downloadOptions.DownloadDestinationPath + return downloadOptions.DownloadDestinationPath, nil + +} diff --git a/common/utils.go b/common/utils.go index fc2e5b12e..5a7edd52a 100644 --- a/common/utils.go +++ b/common/utils.go @@ -1556,3 +1556,12 @@ func JsonifyMapValues(inputMap map[string]interface{}) map[string]interface{} { } return inputMap } + +// IsHTTPURL checks if a string represents an HTTP or HTTPS URL using regular expressions. +func IsHTTPURL(str string) bool { + pattern := `^(http|https)://` + + regex := regexp.MustCompile(pattern) + + return regex.MatchString(str) +} diff --git a/qaengine/engine.go b/qaengine/engine.go index 71300b8e3..d5179f0e0 100644 --- a/qaengine/engine.go +++ b/qaengine/engine.go @@ -21,6 +21,7 @@ import ( "path/filepath" "github.com/konveyor/move2kube/common" + "github.com/konveyor/move2kube/common/download" qatypes "github.com/konveyor/move2kube/types/qaengine" "github.com/sirupsen/logrus" ) @@ -98,6 +99,14 @@ func SetupConfigFile(writeConfigFile string, configStrings, configFiles, presets presetPath := filepath.Join(common.AssetsPath, "built-in", "presets", preset+".yaml") presetPaths = append(presetPaths, presetPath) } + for i, configFile := range configFiles { + if download.IsRemotePath(configFile) { + downloadedPath := download.GetDownloadedPath(configFile, common.RemoteCustomizationsFolder, true) + if downloadedPath != "" { + configFiles[i] = downloadedPath + } + } + } configFiles = append(presetPaths, configFiles...) writeConfig := qatypes.NewConfig(writeConfigFile, configStrings, configFiles, persistPasswords) if writeConfigFile != "" {