-
Notifications
You must be signed in to change notification settings - Fork 39
AGENT-1193: Add --mirror-path flag to support pre-mirrored images #634
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -153,6 +153,12 @@ pullSecret: pull-secret | |
| # [Optional] | ||
| # useBinary: %t | ||
|
|
||
| # Path to pre-mirrored images from oc-mirror workspace. | ||
| # When provided, skips image mirroring and uses the pre-mirrored registry data. | ||
| # The path should point to an oc-mirror workspace directory containing a 'data' subdirectory. | ||
| # [Optional] | ||
| # mirrorPath: /path/to/mirror/workspace | ||
|
|
||
| # Enable all default CatalogSources (on openshift-marketplace namespace). | ||
| # Should be disabled for disconnected environments. | ||
| # Default: false | ||
|
|
@@ -378,7 +384,7 @@ func (a *ApplianceConfig) GetRelease() (string, string, error) { | |
| return "", "", nil | ||
| } | ||
| releaseDigest = strings.Trim(releaseDigest, "'") | ||
| releaseImage = fmt.Sprintf("%s@%s", strings.Split(releaseImage, ":")[0], releaseDigest) | ||
| releaseImage = fmt.Sprintf("%s@%s", releaseImage, releaseDigest) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this change needed?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, it was to handle this error:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, so maybe do this change only when using a custom release image? |
||
| } | ||
| logrus.Debugf("Release image: %s", releaseImage) | ||
| } | ||
|
|
@@ -430,6 +436,11 @@ func (a *ApplianceConfig) validateConfig(f asset.FileFetcher) field.ErrorList { | |
| } | ||
| } | ||
|
|
||
| // Validate mirrorPath | ||
| if err := a.validateMirrorPath(); err != nil { | ||
| allErrs = append(allErrs, err...) | ||
| } | ||
|
|
||
| return allErrs | ||
| } | ||
|
|
||
|
|
@@ -553,6 +564,41 @@ func (a *ApplianceConfig) validatePinnedImageSet() error { | |
| return nil | ||
| } | ||
|
|
||
| func (a *ApplianceConfig) validateMirrorPath() field.ErrorList { | ||
| allErrs := field.ErrorList{} | ||
|
|
||
| if a.Config.MirrorPath != nil { | ||
| mirrorPath := swag.StringValue(a.Config.MirrorPath) | ||
| if mirrorPath != "" { | ||
| // Validate mirror path exists and is a directory | ||
| info, err := os.Stat(mirrorPath) | ||
| if err != nil { | ||
| if os.IsNotExist(err) { | ||
| allErrs = append(allErrs, field.Invalid(field.NewPath("mirrorPath"), | ||
| mirrorPath, "mirror path does not exist")) | ||
| } else { | ||
| allErrs = append(allErrs, field.Invalid(field.NewPath("mirrorPath"), | ||
| mirrorPath, fmt.Sprintf("failed to access mirror path: %v", err))) | ||
| } | ||
| } else if !info.IsDir() { | ||
| allErrs = append(allErrs, field.Invalid(field.NewPath("mirrorPath"), | ||
| mirrorPath, "mirror path must be a directory")) | ||
| } else { | ||
| // Validate data subdirectory exists | ||
| dataDir := filepath.Join(mirrorPath, "data") | ||
| if _, err := os.Stat(dataDir); err != nil { | ||
| allErrs = append(allErrs, field.Invalid(field.NewPath("mirrorPath"), | ||
| mirrorPath, "mirror path must contain a 'data' subdirectory (expected oc-mirror workspace structure)")) | ||
| } | ||
| } | ||
|
|
||
| logrus.Infof("Using pre-mirrored images from: %s", mirrorPath) | ||
| } | ||
| } | ||
|
|
||
| return allErrs | ||
| } | ||
|
|
||
| func (a *ApplianceConfig) storePullSecret() error { | ||
| // Get home dir (~) | ||
| homeDir, err := os.UserHomeDir() | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ import ( | |
| "github.com/go-openapi/swag" | ||
| "github.com/openshift/appliance/pkg/asset/config" | ||
| "github.com/openshift/appliance/pkg/consts" | ||
| "github.com/openshift/appliance/pkg/executer" | ||
| "github.com/openshift/appliance/pkg/genisoimage" | ||
| "github.com/openshift/appliance/pkg/log" | ||
| "github.com/openshift/appliance/pkg/registry" | ||
|
|
@@ -122,7 +123,39 @@ func (a *DataISO) Generate(dependencies asset.Parents) error { | |
| ) | ||
| spinner.FileToMonitor = dataIsoName | ||
| imageGen := genisoimage.NewGenIsoImage(nil) | ||
| if err = imageGen.GenerateImage(envConfig.CacheDir, dataIsoName, filepath.Join(envConfig.TempDir, dataDir), dataVolumeName); err != nil { | ||
|
|
||
| // When mirror-path is provided, copy the Docker registry data from mirror-path/data | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this Generate func is getting a bit too long:) |
||
| // to temp/data so it's in the same location as the registry container image (images/registry/registry.tar) | ||
| registryDataSourcePath := filepath.Join(envConfig.TempDir, dataDir) | ||
| if applianceConfig.Config.MirrorPath != nil && swag.StringValue(applianceConfig.Config.MirrorPath) != "" { | ||
| mirrorDataPath := filepath.Join(swag.StringValue(applianceConfig.Config.MirrorPath), dataDir) | ||
| dockerSrcPath := filepath.Join(mirrorDataPath, "docker") | ||
| dockerDstPath := filepath.Join(registryDataSourcePath, "docker") | ||
|
|
||
| logrus.Infof("Copying Docker registry data from %s to %s", dockerSrcPath, dockerDstPath) | ||
|
|
||
| // Validate source directory exists | ||
| if _, err := os.Stat(dockerSrcPath); err != nil { | ||
| return log.StopSpinner(spinner, fmt.Errorf("docker registry data not found at %s (mirror-path may be invalid): %w", dockerSrcPath, err)) | ||
| } | ||
|
|
||
| // Create destination directory | ||
| if err := os.MkdirAll(registryDataSourcePath, os.ModePerm); err != nil { | ||
| return log.StopSpinner(spinner, fmt.Errorf("failed to create directory for Docker registry data: %w", err)) | ||
| } | ||
|
|
||
| // Copy directory recursively using cp command | ||
| // Note: Paths are safe here as they're program-generated from validated inputs | ||
| cpCmd := fmt.Sprintf("cp -r %s %s", dockerSrcPath, dockerDstPath) | ||
| exec := executer.NewExecuter() | ||
| if _, err := exec.Execute(cpCmd); err != nil { | ||
| return log.StopSpinner(spinner, fmt.Errorf("failed to copy Docker registry data from %s to %s: %w", dockerSrcPath, dockerDstPath, err)) | ||
| } | ||
|
|
||
| logrus.Infof("Successfully copied Docker registry data") | ||
| } | ||
|
|
||
| if err = imageGen.GenerateImage(envConfig.CacheDir, dataIsoName, registryDataSourcePath, dataVolumeName); err != nil { | ||
| return log.StopSpinner(spinner, err) | ||
| } | ||
| return log.StopSpinner(spinner, a.updateAsset(envConfig)) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -138,35 +138,49 @@ func (r *release) execute(command string) (string, error) { | |
| } | ||
|
|
||
| func (r *release) mirrorImages(imageSetFile, blockedImages, additionalImages, operators string) error { | ||
| if err := templates.RenderTemplateFile( | ||
| imageSetFile, | ||
| templates.GetImageSetTemplateData(r.ApplianceConfig, blockedImages, additionalImages, operators), | ||
| r.EnvConfig.TempDir); err != nil { | ||
| return err | ||
| } | ||
| var tempDir string | ||
|
|
||
| imageSetFilePath, err := filepath.Abs(templates.GetFilePathByTemplate(imageSetFile, r.EnvConfig.TempDir)) | ||
| if err != nil { | ||
| return err | ||
| // If a mirror path is provided in appliance-config, use it directly instead of running oc-mirror | ||
| var mirrorPath string | ||
| if r.ApplianceConfig.Config.MirrorPath != nil { | ||
| mirrorPath = *r.ApplianceConfig.Config.MirrorPath | ||
| } | ||
|
|
||
| tempDir := filepath.Join(r.EnvConfig.TempDir, "oc-mirror") | ||
| registryPort := swag.IntValue(r.ApplianceConfig.Config.ImageRegistry.Port) | ||
| cmd := fmt.Sprintf(ocMirror, imageSetFilePath, registryPort, tempDir) | ||
| if mirrorPath != "" { | ||
| logrus.Infof("Using pre-mirrored images from: %s", mirrorPath) | ||
| tempDir = mirrorPath | ||
| } else { | ||
| // Normal mirroring flow - run oc-mirror | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you swap the condition? just for keeping convention. |
||
| if err := templates.RenderTemplateFile( | ||
| imageSetFile, | ||
| templates.GetImageSetTemplateData(r.ApplianceConfig, blockedImages, additionalImages, operators), | ||
| r.EnvConfig.TempDir); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| logrus.Debugf("Fetching image from OCP release (%s)", cmd) | ||
| result, err := r.execute(cmd) | ||
| logrus.Debugf("mirroring result: %s", result) | ||
| if err != nil { | ||
| return err | ||
| imageSetFilePath, err := filepath.Abs(templates.GetFilePathByTemplate(imageSetFile, r.EnvConfig.TempDir)) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| tempDir = filepath.Join(r.EnvConfig.TempDir, "oc-mirror") | ||
| registryPort := swag.IntValue(r.ApplianceConfig.Config.ImageRegistry.Port) | ||
| cmd := fmt.Sprintf(ocMirror, imageSetFilePath, registryPort, tempDir) | ||
|
|
||
| logrus.Debugf("Fetching image from OCP release (%s)", cmd) | ||
| result, err := r.execute(cmd) | ||
| logrus.Debugf("mirroring result: %s", result) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| } | ||
|
|
||
| // Copy generated yaml files to cache dir | ||
| if err = r.copyOutputYamls(tempDir); err != nil { | ||
| // Copy generated yaml files to cache dir (works for both mirror path and oc-mirror output) | ||
| if err := r.copyOutputYamls(tempDir); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| return err | ||
| return nil | ||
| } | ||
|
|
||
| func (r *release) copyOutputYamls(ocMirrorDir string) error { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.