diff --git a/staging/src/github.com/openshift/oc/pkg/cli/admin/release/mirror.go b/staging/src/github.com/openshift/oc/pkg/cli/admin/release/mirror.go index 51fe6f5af495..429522b3f3ed 100644 --- a/staging/src/github.com/openshift/oc/pkg/cli/admin/release/mirror.go +++ b/staging/src/github.com/openshift/oc/pkg/cli/admin/release/mirror.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "io" "os" "sort" "strings" @@ -21,6 +22,7 @@ import ( "k8s.io/client-go/util/retry" kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/kubectl/util/templates" + "sigs.k8s.io/yaml" imagev1 "github.com/openshift/api/image/v1" imageclient "github.com/openshift/client-go/image/clientset/versioned" @@ -269,6 +271,8 @@ func (o *MirrorOptions) Run() error { } } + repositories := make(map[string]struct{}) + // build the mapping list for mirroring and rewrite if necessary for i := range is.Spec.Tags { tag := &is.Spec.Tags[i] @@ -283,6 +287,10 @@ func (o *MirrorOptions) Run() error { return fmt.Errorf("image-references should only contain pointers to images by digest: %s", tag.From.Name) } + // Create a unique map of repos as keys + currentRepo := from.AsRepository().String() + repositories[currentRepo] = struct{}{} + dstMirrorRef := targetFn(tag.Name) mappings = append(mappings, mirror.Mapping{ Source: from, @@ -442,18 +450,64 @@ func (o *MirrorOptions) Run() error { } else { fmt.Fprintf(o.Out, "\nSuccess\nUpdate image: %s\nMirrored to: %s\n", to, o.To) } + + printInstallInstructions(o.Out, o.From, o.To, repositories) return nil } -func sourceImageRef(is *imagev1.ImageStream, name string) (string, bool) { - for _, tag := range is.Spec.Tags { - if tag.Name != name { - continue - } - if tag.From == nil || tag.From.Kind != "DockerImage" { - return "", false - } - return tag.From.Name, true +// printInstallInstructions provides detail to the user for using the new mirror for installs. +// The instructions include yaml formatted output which should be added to the install-config.yaml. +// +// Exmaple output: +// +// +// imageContentSources: +// - sources: +// - mycompany.com/myrepository/repo # destination (mirror) listed first +// - registry.svc.ci.openshift.org/ocp/release # source listed second +// - quay.io/openshift-release-dev/ocp-v4.0-art-dev # repos from image-references +// +func printInstallInstructions(out io.Writer, from, to string, repos map[string]struct{}) error { + type installConfigSubsectionImageContentSources struct { + Sources []string `json:"sources"` + } + type installConfigSubsection struct { + ImageContentSources []installConfigSubsectionImageContentSources `json:"imageContentSources"` } - return "", false + + var repoList []string + + // Append destination (mirror) repo first + mirrorRef, err := imagereference.Parse(to) + if err != nil { + return fmt.Errorf("Unable to parse '--to' image reference: %v", err) + } + mirrorRepo := mirrorRef.AsRepository().String() + repoList = append(repoList, mirrorRepo) + + // Append source repo second + sourceRef, err := imagereference.Parse(from) + if err != nil { + return fmt.Errorf("Unable to parse '--from' image reference: %v", err) + } + sourceRepo := sourceRef.AsRepository().String() + repoList = append(repoList, sourceRepo) + + // Append unordered repos from image-references in release-image + for repo := range repos { + repoList = append(repoList, repo) + } + sources := installConfigSubsectionImageContentSources{ + Sources: repoList} + imageContentSource := installConfigSubsection{ + ImageContentSources: []installConfigSubsectionImageContentSources{sources}} + result, err := yaml.Marshal(imageContentSource) + if err != nil { + return fmt.Errorf("Unable to marshal imageContentSource yaml: %v", err) + } + + fmt.Fprintf(out, "\nTo use the new mirrored release-image to install, provide the following list of release-image sources to the installer using the install-config.yaml:\n") + fmt.Fprintf(out, string(result)) + + return nil }