Skip to content

Commit

Permalink
Extend -b option to accept docker/http/https scheme
Browse files Browse the repository at this point in the history
This patch enable user to use `-b` option in different ways for
`crc config`, `crc setup` and `crc start`.

```
$ crc config set bundle <local_bundle_path or http://foo.com/bundle or docker://registry.com/bundle:version>

$ crc setup -b <local_bundle_path or http://foo.com/bundle or docker://registry.com/bundle:version>

$ crc start -b <local_bundle_path or http://foo.com/bundle or docker://registry.com/bundle:version>
```

Assumption here is user doesn't change the bundle name during upload to
different location (like fileshare or registry) since we are building
the bundleName using those info.
  • Loading branch information
praveenkumar committed Sep 19, 2022
1 parent 9f5c378 commit 35faa01
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 34 deletions.
3 changes: 2 additions & 1 deletion pkg/crc/config/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ func RegisterSettings(cfg *Config) {
fmt.Sprintf("Virtual machine preset (valid values are: %s, %s and %s)", preset.Podman, preset.OpenShift, preset.OKD))
// Start command settings in config
cfg.AddSetting(Bundle, defaultBundlePath(cfg), validateBundlePath, SuccessfullyApplied,
fmt.Sprintf("Bundle path (string, default '%s')", defaultBundlePath(cfg)))
fmt.Sprintf("Bundle path/URI - absolute or local path, http, https or docker URI (string, like 'https://foo.com/%s', 'docker://quay.io/myorg/%s:%s' default '%s' )",
constants.GetDefaultBundle(GetPreset(cfg)), constants.GetDefaultBundle(GetPreset(cfg)), version.GetCRCVersion(), defaultBundlePath(cfg)))
cfg.AddSetting(CPUs, defaultCPUs(cfg), validateCPUs, RequiresRestartMsg,
fmt.Sprintf("Number of CPU cores (must be greater than or equal to '%d')", defaultCPUs(cfg)))
cfg.AddSetting(Memory, defaultMemory(cfg), validateMemory, RequiresRestartMsg,
Expand Down
60 changes: 51 additions & 9 deletions pkg/crc/machine/bundle/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package bundle
import (
"fmt"
"os"
"path"
"path/filepath"
"regexp"
"runtime"
Expand All @@ -12,7 +13,8 @@ import (

"github.com/Masterminds/semver/v3"
"github.com/code-ready/crc/pkg/crc/constants"
"github.com/code-ready/crc/pkg/crc/preset"
"github.com/code-ready/crc/pkg/crc/image"
crcPreset "github.com/code-ready/crc/pkg/crc/preset"
"github.com/code-ready/crc/pkg/download"
)

Expand Down Expand Up @@ -174,19 +176,19 @@ func (bundle *CrcBundleInfo) GetBundleNameWithoutExtension() string {
return GetBundleNameWithoutExtension(bundle.GetBundleName())
}

func (bundle *CrcBundleInfo) GetBundleType() preset.Preset {
func (bundle *CrcBundleInfo) GetBundleType() crcPreset.Preset {
switch bundle.Type {
case "snc", "snc_custom":
return preset.OpenShift
return crcPreset.OpenShift
case "podman", "podman_custom":
return preset.Podman
return crcPreset.Podman
default:
return preset.OpenShift
return crcPreset.OpenShift
}
}

func (bundle *CrcBundleInfo) IsOpenShift() bool {
return bundle.GetBundleType() == preset.OpenShift
return bundle.GetBundleType() == crcPreset.OpenShift
}

func (bundle *CrcBundleInfo) verify() error {
Expand Down Expand Up @@ -250,10 +252,24 @@ func GetCustomBundleName(bundleFilename string) string {
return fmt.Sprintf("%s_%d%s", baseName, time.Now().Unix(), bundleExtension)
}

type presetDownloadInfo map[preset.Preset]*download.RemoteFile
func GetBundleNameFromURI(bundleURI string) string {
// the URI is expected to have been validated by validation.ValidateBundlePath first
switch {
case strings.HasPrefix(bundleURI, "docker://"):
imageAndTag := strings.Split(path.Base(bundleURI), ":")
return constants.BundleForPreset(image.GetPresetName(imageAndTag[0]), imageAndTag[1])
case strings.HasPrefix(bundleURI, "http://"), strings.HasPrefix(bundleURI, "https://"):
return path.Base(bundleURI)
default:
// local path
return filepath.Base(bundleURI)
}
}

type presetDownloadInfo map[crcPreset.Preset]*download.RemoteFile
type bundlesDownloadInfo map[string]presetDownloadInfo

func getBundleDownloadInfo(preset preset.Preset) (*download.RemoteFile, error) {
func getBundleDownloadInfo(preset crcPreset.Preset) (*download.RemoteFile, error) {
bundles, ok := bundleLocations[runtime.GOARCH]
if !ok {
return nil, fmt.Errorf("Unsupported architecture: %s", runtime.GOARCH)
Expand All @@ -270,7 +286,7 @@ func getBundleDownloadInfo(preset preset.Preset) (*download.RemoteFile, error) {
return downloadInfo, nil
}

func DownloadDefault(preset preset.Preset) error {
func DownloadDefault(preset crcPreset.Preset) error {
downloadInfo, err := getBundleDownloadInfo(preset)
if err != nil {
return err
Expand All @@ -288,3 +304,29 @@ func DownloadDefault(preset preset.Preset) error {

return nil
}

func Download(preset crcPreset.Preset, bundleURI string) (string, error) {
// If we are asked to download
// ~/.crc/cache/crc_podman_libvirt_4.1.1.crcbundle, this means we want
// are downloading the default bundle for this release. This uses a
// different codepath from user-specified URIs as for the default
// bundles, their sha256sums are known and can be checked.
if bundleURI == constants.GetDefaultBundlePath(preset) {
if preset == crcPreset.OpenShift {
return bundleURI, DownloadDefault(preset)
}
return bundleURI, image.PullBundle(preset, "")
}
switch {
case strings.HasPrefix(bundleURI, "http://"), strings.HasPrefix(bundleURI, "https://"):
return download.Download(bundleURI, constants.MachineCacheDir, 0644, nil)
case strings.HasPrefix(bundleURI, "docker://"):
if err := image.PullBundle(preset, bundleURI); err != nil {
return "", err
}
bundlePath := filepath.Join(constants.MachineCacheDir, GetBundleNameFromURI(bundleURI))
return bundlePath, nil
}
// the `bundleURI` parameter turned out to be a local path
return bundleURI, nil
}
10 changes: 7 additions & 3 deletions pkg/crc/machine/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,17 @@ import (

const minimumMemoryForMonitoring = 14336

func getCrcBundleInfo(bundleName, bundlePath string) (*bundle.CrcBundleInfo, error) {
func getCrcBundleInfo(preset crcPreset.Preset, bundleName, bundlePath string) (*bundle.CrcBundleInfo, error) {
bundleInfo, err := bundle.Use(bundleName)
if err == nil {
logging.Infof("Loading bundle: %s...", bundleName)
return bundleInfo, nil
}
logging.Debugf("Failed to load bundle %s: %v", bundleName, err)
bundlePath, err = bundle.Download(preset, bundlePath)
if err != nil {
return nil, err
}
logging.Infof("Extracting bundle: %s...", bundleName)
if _, err := bundle.Extract(bundlePath); err != nil {
return nil, err
Expand Down Expand Up @@ -195,8 +199,8 @@ func (client *client) Start(ctx context.Context, startConfig types.StartConfig)
return nil, errors.Wrap(err, "Cannot determine if VM exists")
}

bundleName := bundle.GetBundleNameWithoutExtension(filepath.Base(startConfig.BundlePath))
crcBundleMetadata, err := getCrcBundleInfo(bundleName, startConfig.BundlePath)
bundleName := bundle.GetBundleNameWithoutExtension(bundle.GetBundleNameFromURI(startConfig.BundlePath))
crcBundleMetadata, err := getCrcBundleInfo(startConfig.Preset, bundleName, startConfig.BundlePath)
if err != nil {
return nil, errors.Wrap(err, "Error getting bundle metadata")
}
Expand Down
21 changes: 5 additions & 16 deletions pkg/crc/preflight/preflight_checks_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"github.com/code-ready/crc/pkg/crc/adminhelper"
"github.com/code-ready/crc/pkg/crc/cluster"
"github.com/code-ready/crc/pkg/crc/constants"
"github.com/code-ready/crc/pkg/crc/image"
"github.com/code-ready/crc/pkg/crc/logging"
"github.com/code-ready/crc/pkg/crc/machine/bundle"
crcpreset "github.com/code-ready/crc/pkg/crc/preset"
Expand Down Expand Up @@ -63,7 +62,7 @@ var genericCleanupChecks = []Check{
func checkBundleExtracted(bundlePath string) func() error {
return func() error {
logging.Infof("Checking if %s exists", bundlePath)
bundleName := filepath.Base(bundlePath)
bundleName := bundle.GetBundleNameFromURI(bundlePath)
if _, err := bundle.Get(bundleName); err != nil {
logging.Debugf("error getting bundle info for %s: %v", bundleName, err)
return err
Expand Down Expand Up @@ -97,20 +96,10 @@ func fixBundleExtracted(bundlePath string, preset crcpreset.Preset) func() error
return fmt.Errorf("%s is invalid or missing, run 'crc setup' to download the bundle", bundlePath)
}
}
if bundlePath == constants.GetDefaultBundlePath(preset) {
logging.Infof("Downloading %s", constants.GetDefaultBundle(preset))
// In case of OKD or podman bundle then pull the bundle image from quay
// otherwise use mirror location to download the bundle.
if preset == crcpreset.OKD || preset == crcpreset.Podman {
if err := image.PullBundle(preset, ""); err != nil {
return err
}
} else {
if err := bundle.DownloadDefault(preset); err != nil {
return err
}
}
bundlePath = constants.GetDefaultBundlePath(preset)

var err error
if bundlePath, err = bundle.Download(preset, bundlePath); err != nil {
return err
}

logging.Infof("Uncompressing %s", bundlePath)
Expand Down
40 changes: 35 additions & 5 deletions pkg/crc/validation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import (
"errors"
"fmt"
"net"
"net/url"
"os"
"path/filepath"
"strings"

"github.com/code-ready/crc/pkg/crc/constants"
"github.com/code-ready/crc/pkg/crc/image"
"github.com/code-ready/crc/pkg/crc/logging"
"github.com/code-ready/crc/pkg/crc/machine/bundle"
crcpreset "github.com/code-ready/crc/pkg/crc/preset"
Expand Down Expand Up @@ -56,17 +57,26 @@ func ValidateEnoughMemory(value int) error {

// ValidateBundlePath checks if the provided bundle path exist
func ValidateBundlePath(bundlePath string, preset crcpreset.Preset) error {
if err := ValidatePath(bundlePath); err != nil {
return err
logging.Debugf("Got bundle path: %s", bundlePath)
if err := ValidateURL(bundlePath); err != nil {
var urlError *url.Error
// Some local paths (for example relative paths) can't be parsed/validated by `ValidateURL` and will be validated here
if errors.As(err, &urlError) {
if err1 := ValidatePath(bundlePath); err1 != nil {
return err1
}
} else {
return err
}
}

userProvidedBundle := filepath.Base(bundlePath)
userProvidedBundle := bundle.GetBundleNameFromURI(bundlePath)
bundleMismatchWarning(userProvidedBundle, preset)
return nil
}

func ValidateBundle(bundlePath string, preset crcpreset.Preset) error {
bundleName := filepath.Base(bundlePath)
bundleName := bundle.GetBundleNameFromURI(bundlePath)
bundleMetadata, err := bundle.Get(bundleName)
if err != nil {
return ValidateBundlePath(bundlePath, preset)
Expand Down Expand Up @@ -100,6 +110,26 @@ func ValidateIPAddress(ipAddress string) error {
return nil
}

func ValidateURL(uri string) error {
u, err := url.ParseRequestURI(uri)
if err != nil {
logging.Debugf("Failed to parse url: %v", err)
return err
}
switch {
// If uri string is without scheme then check if it is a valid absolute path.
// Relative paths will cause `ParseRequestURI` to error out, and will be handled in `ValidateBundlePath`
case !u.IsAbs():
return ValidatePath(uri)
case u.Scheme == "http", u.Scheme == "https":
return nil
case u.Scheme == "docker":
return image.ValidateURI(u)
default:
return fmt.Errorf("invalid %s format (only supported http, https or docker)", uri)
}
}

type InvalidPath struct {
path string
}
Expand Down

0 comments on commit 35faa01

Please sign in to comment.