diff --git a/pkg/crc/machine/bundle/metadata.go b/pkg/crc/machine/bundle/metadata.go index 2eead2a612..79273dba63 100644 --- a/pkg/crc/machine/bundle/metadata.go +++ b/pkg/crc/machine/bundle/metadata.go @@ -52,6 +52,14 @@ type ClusterInfo struct { OpenshiftPullSecret string `json:"openshiftPullSecret,omitempty"` } +type FilenameInfo struct { + Preset crcPreset.Preset + Driver string + Version string + Arch string + CustomBundleSuffix string +} + type Node struct { Kind []string `json:"kind"` Hostname string `json:"hostname"` @@ -244,6 +252,35 @@ func GetBundleNameFromURI(bundleURI string) string { } } +// GetBundleInfoFromName Parses the bundle filename and returns a FilenameInfo struct +func GetBundleInfoFromName(bundleName string) (*FilenameInfo, error) { + var filenameInfo FilenameInfo + + // crc_preset_driver_version_arch_customSuffix.crcbundle + bundleNameRegex := regexp.MustCompile(`crc(?:(?:_)([[:alpha:]]+))?_([[:alpha:]]+)_([0-9.]+)_([[:alnum:]]+)(?:(?:_)([0-9]+))?\.crcbundle`) + filenameParts := bundleNameRegex.FindStringSubmatch(bundleName) + + if filenameParts == nil { + return &filenameInfo, fmt.Errorf("bundle filename is in unrecognized format") + } + + if filenameParts[1] == "" { + filenameInfo.Preset = crcPreset.OpenShift + } else { + parsedPreset, err := crcPreset.ParsePresetE(filenameParts[1]) + if err != nil { + return &filenameInfo, err + } + filenameInfo.Preset = parsedPreset + } + filenameInfo.Driver = filenameParts[2] + filenameInfo.Version = filenameParts[3] + filenameInfo.Arch = filenameParts[4] + filenameInfo.CustomBundleSuffix = filenameParts[5] + + return &filenameInfo, nil +} + func getBundleDownloadInfo(preset crcPreset.Preset) (*download.RemoteFile, error) { sha256sum, err := getDefaultBundleVerifiedHash(preset) if err != nil { diff --git a/pkg/crc/machine/bundle/metadata_test.go b/pkg/crc/machine/bundle/metadata_test.go index 61134f9b0b..1088ab282f 100644 --- a/pkg/crc/machine/bundle/metadata_test.go +++ b/pkg/crc/machine/bundle/metadata_test.go @@ -211,3 +211,83 @@ func testDataURI(t *testing.T, sha256sum string) string { require.NoError(t, err) return fmt.Sprintf("file://%s", filepath.ToSlash(absPath)) } + +func TestGetBundleInfoFromNameValid(t *testing.T) { + valid := [][]string{ + // crc_preset_driver_version_arch_customSuffix.crcbundle + {"crc_libvirt_4.16.7_amd64.crcbundle", preset.OpenShift.String(), "libvirt", "4.16.7", "amd64", ""}, + {"crc_libvirt_4.16.7_amd64_232.crcbundle", preset.OpenShift.String(), "libvirt", "4.16.7", "amd64", "232"}, + {"crc_microshift_libvirt_4.16.7_amd64.crcbundle", preset.Microshift.String(), "libvirt", "4.16.7", "amd64", ""}, + {"crc_microshift_libvirt_4.16.7_amd64_2345.crcbundle", preset.Microshift.String(), "libvirt", "4.16.7", "amd64", "2345"}, + {"crc_okd_vfkit_4.16.7_amd64.crcbundle", preset.OKD.String(), "vfkit", "4.16.7", "amd64", ""}, + {"crc_okd_vfkit_4.16.7_amd64_2342465234654.crcbundle", preset.OKD.String(), "vfkit", "4.16.7", "amd64", "2342465234654"}, + {"crc_hyperv_4.18.0_arm64.crcbundle", preset.OpenShift.String(), "hyperv", "4.18.0", "arm64", ""}, + + {"crc_hyperv_4.18_x86.crcbundle", preset.OpenShift.String(), "hyperv", "4.18", "x86", ""}, + {"crc_microshift_hyperv_4.18_x86.crcbundle", preset.Microshift.String(), "hyperv", "4.18", "x86", ""}, + {"crc_microshift_hyperv_4.18_x86_1233.crcbundle", preset.Microshift.String(), "hyperv", "4.18", "x86", "1233"}, + {"crc_hyperv_4.18_x86_4566.crcbundle", preset.OpenShift.String(), "hyperv", "4.18", "x86", "4566"}, + {"crc_ABCdrv_4.18.0_x86_4566.crcbundle", preset.OpenShift.String(), "ABCdrv", "4.18.0", "x86", "4566"}, + {"crc_ABCdrv_4.18.1.2_x86_4566.crcbundle", preset.OpenShift.String(), "ABCdrv", "4.18.1.2", "x86", "4566"}, + {"crc_hyperv_4.18_x86.crcbundle", preset.OpenShift.String(), "hyperv", "4.18", "x86", ""}, + {"crc_ABCdrv_4.18.0_x86.crcbundle", preset.OpenShift.String(), "ABCdrv", "4.18.0", "x86", ""}, + {"crc_ABCdrv_4.18.1.2_x86.crcbundle", preset.OpenShift.String(), "ABCdrv", "4.18.1.2", "x86", ""}, + {"crc_hyperv_4.18_64bit.crcbundle", preset.OpenShift.String(), "hyperv", "4.18", "64bit", ""}, + {"crc_hyperv_4.1_64bit.crcbundle", preset.OpenShift.String(), "hyperv", "4.1", "64bit", ""}, + + {"crc_openshift_libvirt_4.16.7_amd64.crcbundle", preset.OpenShift.String(), "libvirt", "4.16.7", "amd64", ""}, + {"crc_openshift_libvirt_4.16.7_amd64_1.crcbundle", preset.OpenShift.String(), "libvirt", "4.16.7", "amd64", "1"}, + {"crc_openshift_libvirt_00.00.00.00_amd64.crcbundle", preset.OpenShift.String(), "libvirt", "00.00.00.00", "amd64", ""}, + {"crc_openshift_libvirt_00.00.00.00_amd64_100.crcbundle", preset.OpenShift.String(), "libvirt", "00.00.00.00", "amd64", "100"}, + {"crc_libvirt_4.16.7_intel.crcbundle", preset.OpenShift.String(), "libvirt", "4.16.7", "intel", ""}, + {"crc_libvirt_4.16.7_intel_23.crcbundle", preset.OpenShift.String(), "libvirt", "4.16.7", "intel", "23"}, + {"crc_libvirt_4.16.7_64.crcbundle", preset.OpenShift.String(), "libvirt", "4.16.7", "64", ""}, + {"crc_libvirt_4.16.7_64_132.crcbundle", preset.OpenShift.String(), "libvirt", "4.16.7", "64", "132"}, + {"crc_microshift_libvirt_4.16.7_64.crcbundle", preset.Microshift.String(), "libvirt", "4.16.7", "64", ""}, + {"crc_microshift_libvirt_4.16.7_64_123.crcbundle", preset.Microshift.String(), "libvirt", "4.16.7", "64", "123"}, + {"crc_libvirt_4_amd64.crcbundle", preset.OpenShift.String(), "libvirt", "4", "amd64", ""}, + {"crc_libvirt_4_amd64_0123.crcbundle", preset.OpenShift.String(), "libvirt", "4", "amd64", "0123"}, + {"crc_okd_libvirt_4_amd64.crcbundle", preset.OKD.String(), "libvirt", "4", "amd64", ""}, + {"crc_okd_libvirt_4_amd64_0123.crcbundle", preset.OKD.String(), "libvirt", "4", "amd64", "0123"}, + } + + for _, parts := range valid { + bundleInfo, err := GetBundleInfoFromName(parts[0]) + assert.NoError(t, err) + assert.Equal(t, bundleInfo.Preset.String(), parts[1]) + assert.Equal(t, bundleInfo.Driver, parts[2]) + assert.Equal(t, bundleInfo.Version, parts[3]) + assert.Equal(t, bundleInfo.Arch, parts[4]) + assert.Equal(t, bundleInfo.CustomBundleSuffix, parts[5]) + } +} + +func TestGetBundleInfoFromNameInvalid(t *testing.T) { + // missing version + _, err := GetBundleInfoFromName("crc_libvirt_amd64.crcbundle") + assert.Error(t, err) + + // missing crc prefix + _, err = GetBundleInfoFromName("libvirt_4.16.0_amd64.crcbundle") + assert.Error(t, err) + + // missing arch + _, err = GetBundleInfoFromName("crc_microshift_libvirt_4.7.0.crcbundle") + assert.Error(t, err) + + // non numeric suffix + _, err = GetBundleInfoFromName("crc_microshift_libvirt_4.7.0_x86_custom.crcbundle") + assert.Error(t, err) + + // missing driver + _, err = GetBundleInfoFromName("crc_4.16.2_amd64_123.crcbundle") + assert.Error(t, err) + + // missing driver and version + _, err = GetBundleInfoFromName("crc_amd64_123.crcbundle") + assert.Error(t, err) + + // unknown preset + _, err = GetBundleInfoFromName("crc_nanoshift_libvirt_4.16.7_amd64_232.crcbundle") + assert.Error(t, err) +} diff --git a/pkg/crc/machine/start.go b/pkg/crc/machine/start.go index 1832fddf04..cad83b8aea 100644 --- a/pkg/crc/machine/start.go +++ b/pkg/crc/machine/start.go @@ -284,7 +284,7 @@ func (client *client) Start(ctx context.Context, startConfig types.StartConfig) return nil, errors.Wrap(err, "Error getting bundle metadata") } - if err := bundleMismatchWithPreset(startConfig.Preset, crcBundleMetadata); err != nil { + if err := validation.BundleMismatchWithPresetMetadata(startConfig.Preset, crcBundleMetadata); err != nil { return nil, err } @@ -854,13 +854,6 @@ func updateKubeconfig(ctx context.Context, ocConfig oc.Config, sshRunner *crcssh return nil } -func bundleMismatchWithPreset(preset crcPreset.Preset, bundleMetadata *bundle.CrcBundleInfo) error { - if preset != bundleMetadata.GetBundleType() { - return errors.Errorf("Preset %s is used but bundle is provided for %s preset", preset, bundleMetadata.GetBundleType()) - } - return nil -} - func startMicroshift(ctx context.Context, sshRunner *crcssh.Runner, ocConfig oc.Config, pullSec cluster.PullSecretLoader) error { logging.Infof("Starting Microshift service... [takes around 1min]") if err := ensurePullSecretPresentInVM(sshRunner, pullSec); err != nil { diff --git a/pkg/crc/validation/validation.go b/pkg/crc/validation/validation.go index f7307ef4a2..3e8ee9496b 100644 --- a/pkg/crc/validation/validation.go +++ b/pkg/crc/validation/validation.go @@ -95,8 +95,28 @@ func ValidateBundle(bundlePath string, preset crcpreset.Preset) error { if bundlePath == constants.GetDefaultBundlePath(preset) { return nil } - return ValidateBundlePath(bundlePath, preset) + + if err := ValidateBundlePath(bundlePath, preset); err != nil { + return err + } + + bundleInfo, err := bundle.GetBundleInfoFromName(bundleName) + if err != nil { + return err + } + + if err := BundleMismatchWithPresetFilename(preset, bundleInfo); err != nil { + logging.Fatal(err.Error()) + return err + } + return nil + } + + if err := BundleMismatchWithPresetMetadata(preset, bundleMetadata); err != nil { + logging.Fatal(err.Error()) + return err } + bundleMismatchWarning(bundleMetadata.GetBundleName(), preset) /* 'bundle' is already unpacked in ~/.crc/cache */ return nil @@ -117,6 +137,24 @@ func bundleMismatchWarning(userProvidedBundle string, preset crcpreset.Preset) { } } +// BundleMismatchWithPresetFilename checks whether the bundle matches the configured preset based on the bundle filename +// (bundle is not downloaded or uncompressed yet) +func BundleMismatchWithPresetFilename(preset crcpreset.Preset, bundleFilenameInfo *bundle.FilenameInfo) error { + if preset != bundleFilenameInfo.Preset { + return fmt.Errorf("Preset %s is used but bundle is provided for %s preset", preset, bundleFilenameInfo.Preset) + } + return nil +} + +// BundleMismatchWithPresetMetadata checks whether the bundle matches the configured preset based on the bundle metadata +// (bundle is already downloaded and uncompressed) +func BundleMismatchWithPresetMetadata(preset crcpreset.Preset, bundleMetadata *bundle.CrcBundleInfo) error { + if preset != bundleMetadata.GetBundleType() { + return fmt.Errorf("Preset %s is used but bundle is provided for %s preset", preset, bundleMetadata.GetBundleType()) + } + return nil +} + // ValidateIPAddress checks if provided IP is valid func ValidateIPAddress(ipAddress string) error { ip := net.ParseIP(ipAddress).To4()