Skip to content

Commit

Permalink
Add generation of updateService.yaml (#746)
Browse files Browse the repository at this point in the history
  • Loading branch information
sherine-k committed Dec 11, 2023
1 parent cfcfcef commit 2311da0
Show file tree
Hide file tree
Showing 27 changed files with 736 additions and 258 deletions.
2 changes: 1 addition & 1 deletion v2/pkg/archive/archive_test.go
Expand Up @@ -51,7 +51,7 @@ var expectedTarContents = []string{
"isc",
"working-dir-fake/hold-release/ocp-release/4.14.1-x86_64/release-manifests/image-references",
"working-dir-fake/hold-release/ocp-release/4.14.1-x86_64/release-manifests/release-metadata",
"working-dir-fake/release-filters/d5f8153de54b0327ad20d24d4dbba7a6"}
"working-dir-fake/release-filters/690d64d2ebd41f1834c80e632f041b5b"}

func newMirrorArchiveWithMocks(testFolder string) (MirrorArchive, error) {
global := &mirror.GlobalOptions{
Expand Down
20 changes: 18 additions & 2 deletions v2/pkg/cli/executor.go
Expand Up @@ -368,7 +368,7 @@ func (o *ExecutorSchema) Complete(args []string) error {
o.Release = release.New(o.Log, o.Config, o.Opts, o.Mirror, o.Manifest, cn, o.LocalStorageFQDN, o.ImageBuilder)
o.Operator = operator.New(o.Log, o.Config, o.Opts, o.Mirror, o.Manifest, o.LocalStorageFQDN)
o.AdditionalImages = additional.New(o.Log, o.Config, o.Opts, o.Mirror, o.Manifest, o.LocalStorageFQDN)
o.ClusterResources = clusterresources.New(o.Log, o.Config, o.Opts)
o.ClusterResources = clusterresources.New(o.Log, o.Opts.Global.WorkingDir)

if o.Opts.IsMirrorToDisk() {
o.MirrorArchiver, err = archive.NewMirrorArchive(&o.Opts, rootDir, o.Opts.Global.ConfigPath, o.Opts.Global.WorkingDir, o.LocalStorageDisk, o.Log)
Expand Down Expand Up @@ -547,11 +547,27 @@ func (o *ExecutorSchema) RunDiskToMirror(cmd *cobra.Command, args []string) erro
return err
}
//create IDMS/ITMS
err = o.ClusterResources.IDMSGenerator(cmd.Context(), allImages, o.Opts)
err = o.ClusterResources.IDMSGenerator(allImages)
if err != nil {
return err
}

// create updateService
if o.Config.Mirror.Platform.Graph {
graphImage, err := o.Release.GraphImage()
if err != nil {
return err
}
releaseImage, err := o.Release.ReleaseImage()
if err != nil {
return err
}
err = o.ClusterResources.UpdateServiceGenerator(graphImage, releaseImage)
if err != nil {
return err
}
}

mirrorFinish := time.Now()
o.Log.Info("start time : %v", startTime)
o.Log.Info("collection time : %v", collectionFinish)
Expand Down
8 changes: 8 additions & 0 deletions v2/pkg/cli/executor_test.go
Expand Up @@ -292,6 +292,14 @@ func (o *Collector) ReleaseImageCollector(ctx context.Context) ([]v1alpha3.CopyI
return test, nil
}

func (o *Collector) GraphImage() (string, error) {
return "localhost:5000/openshift/graph-image:latest", nil
}

func (o *Collector) ReleaseImage() (string, error) {
return "quay.io/openshift-release-dev/ocp-release:4.13.10-x86_64", nil
}

func (o *Collector) AdditionalImagesCollector(ctx context.Context) ([]v1alpha3.CopyImageSchema, error) {
if o.Fail {
return []v1alpha3.CopyImageSchema{}, fmt.Errorf("forced error release collector")
Expand Down
84 changes: 66 additions & 18 deletions v2/pkg/clusterresources/clusterresources.go
@@ -1,7 +1,7 @@
package clusterresources

import (
"context"
"bytes"
"errors"
"fmt"
"os"
Expand All @@ -10,32 +10,26 @@ import (
"time"

confv1 "github.com/openshift/api/config/v1"
"github.com/openshift/oc-mirror/v2/pkg/api/v1alpha2"
"github.com/openshift/oc-mirror/v2/pkg/api/v1alpha3"
updateservicev1 "github.com/openshift/oc-mirror/v2/pkg/clusterresources/updateservice/v1"
"github.com/openshift/oc-mirror/v2/pkg/image"
clog "github.com/openshift/oc-mirror/v2/pkg/log"
"github.com/openshift/oc-mirror/v2/pkg/mirror"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/yaml"
)

const (
clusterResourcesDir string = "cluster-resources"
)

func New(log clog.PluggableLoggerInterface,
config v1alpha2.ImageSetConfiguration,
opts mirror.CopyOptions,
workingDir string,
) GeneratorInterface {
return &ClusterResourcesGenerator{Log: log, Config: config, Opts: opts}
return &ClusterResourcesGenerator{Log: log, WorkingDir: workingDir}
}

type ClusterResourcesGenerator struct {
Log clog.PluggableLoggerInterface
Config v1alpha2.ImageSetConfiguration
Opts mirror.CopyOptions
Log clog.PluggableLoggerInterface
WorkingDir string
}

func (c *ClusterResourcesGenerator) IDMSGenerator(ctx context.Context, allRelatedImages []v1alpha3.CopyImageSchema, opts mirror.CopyOptions) error {
func (o *ClusterResourcesGenerator) IDMSGenerator(allRelatedImages []v1alpha3.CopyImageSchema) error {

// determine the name of the IDMS resource
// TODO determine name (based on date?)
Expand All @@ -46,7 +40,7 @@ func (c *ClusterResourcesGenerator) IDMSGenerator(ctx context.Context, allRelate
name := "idms-" + dateTime

// locate the output directory
idmsFileName := filepath.Join(opts.Global.WorkingDir, clusterResourcesDir, name+".yaml")
idmsFileName := filepath.Join(o.WorkingDir, clusterResourcesDir, name+".yaml")

// create a IDMS struct
idms := confv1.ImageDigestMirrorSet{
Expand Down Expand Up @@ -83,18 +77,18 @@ func (c *ClusterResourcesGenerator) IDMSGenerator(ctx context.Context, allRelate

// save IDMS struct to file
if _, err := os.Stat(idmsFileName); errors.Is(err, os.ErrNotExist) {
c.Log.Info("%s does not exist, creating it", idmsFileName)
o.Log.Info("%s does not exist, creating it", idmsFileName)
err := os.MkdirAll(filepath.Dir(idmsFileName), 0755)
if err != nil {
return err
}
c.Log.Info("%s dir created", filepath.Dir(idmsFileName))
o.Log.Info("%s dir created", filepath.Dir(idmsFileName))
}
idmsFile, err := os.Create(idmsFileName)
if err != nil {
return err
}
c.Log.Info("%s file created", idmsFileName)
o.Log.Info("%s file created", idmsFileName)

defer idmsFile.Close()

Expand Down Expand Up @@ -147,3 +141,57 @@ func generateImageMirrors(allRelatedImages []v1alpha3.CopyImageSchema) (map[stri
}
return mirrors, nil
}

func (o *ClusterResourcesGenerator) UpdateServiceGenerator(graphImage, releaseImageRef string) error {
// truncate tag or digest from release image
// according to https://docs.openshift.com/container-platform/4.14/updating/updating_a_cluster/updating_disconnected_cluster/disconnected-update-osus.html#update-service-create-service-cli_updating-restricted-network-cluster-osus
releaseImage, err := image.ParseRef(releaseImageRef)
if err != nil {
return err
}
releaseImageName := releaseImage.Name
osus := updateservicev1.UpdateService{
TypeMeta: metav1.TypeMeta{
APIVersion: updateservicev1.GroupVersion.String(),
Kind: updateServiceResourceKind,
},
ObjectMeta: metav1.ObjectMeta{
Name: updateServiceResourceName,
},
Spec: updateservicev1.UpdateServiceSpec{
Replicas: 2,
Releases: releaseImageName,
GraphDataImage: graphImage,
},
}

// put UpdateService in yaml
osusBytes, err := yaml.Marshal(osus)
if err != nil {
return err
}
// creationTimestamp is a struct, omitempty does not apply
osusBytes = bytes.ReplaceAll(osusBytes, []byte(" creationTimestamp: null\n"), []byte(""))

// save UpdateService struct to file
osusPath := filepath.Join(o.WorkingDir, clusterResourcesDir, updateServiceFilename)

if _, err := os.Stat(osusPath); errors.Is(err, os.ErrNotExist) {
o.Log.Info("%s does not exist, creating it", osusPath)
err := os.MkdirAll(filepath.Dir(osusPath), 0755)
if err != nil {
return err
}
o.Log.Info("%s dir created", filepath.Dir(osusPath))
}
osusFile, err := os.Create(osusPath)
if err != nil {
return err
}
o.Log.Info("%s file created", osusPath)

defer osusFile.Close()

_, err = osusFile.Write(osusBytes)
return err
}
112 changes: 62 additions & 50 deletions v2/pkg/clusterresources/clusterresources_test.go
@@ -1,65 +1,26 @@
package clusterresources

import (
"context"
"os"
"path/filepath"
"regexp"
"strings"
"testing"

"github.com/openshift/oc-mirror/v2/pkg/api/v1alpha2"
"github.com/openshift/oc-mirror/v2/pkg/api/v1alpha3"
updateservicev1 "github.com/openshift/oc-mirror/v2/pkg/clusterresources/updateservice/v1"
clog "github.com/openshift/oc-mirror/v2/pkg/log"
"github.com/openshift/oc-mirror/v2/pkg/mirror"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/yaml"
)

func TestIDMSGenerator(t *testing.T) {
log := clog.New("trace")

tmpDir := t.TempDir()
globalD2M := &mirror.GlobalOptions{
TlsVerify: false,
SecurePolicy: false,
WorkingDir: tmpDir + "/working-dir",
From: tmpDir,
}

_, sharedOpts := mirror.SharedImageFlags()
_, deprecatedTLSVerifyOpt := mirror.DeprecatedTLSVerifyFlags()
_, srcOptsD2M := mirror.ImageSrcFlags(globalD2M, sharedOpts, deprecatedTLSVerifyOpt, "src-", "screds")
_, destOptsD2M := mirror.ImageDestFlags(globalD2M, sharedOpts, deprecatedTLSVerifyOpt, "dest-", "dcreds")
_, retryOpts := mirror.RetryFlags()

d2mOpts := mirror.CopyOptions{
Global: globalD2M,
DeprecatedTLSVerify: deprecatedTLSVerifyOpt,
SrcImage: srcOptsD2M,
DestImage: destOptsD2M,
RetryOpts: retryOpts,
Destination: "docker://localhost:5000/test",
Dev: false,
Mode: mirror.DiskToMirror,
}

cfgd2m := v1alpha2.ImageSetConfiguration{
ImageSetConfigurationSpec: v1alpha2.ImageSetConfigurationSpec{
Mirror: v1alpha2.Mirror{
Platform: v1alpha2.Platform{
Architectures: []string{"amd64"},
Channels: []v1alpha2.ReleaseChannel{
{
Name: "stable-4.13",
MinVersion: "4.13.9",
MaxVersion: "4.13.10",
},
},
},
},
},
}
workingDir := tmpDir + "/working-dir"

ctx := context.Background()
defer os.RemoveAll(tmpDir)

imageList := []v1alpha3.CopyImageSchema{
{
Expand Down Expand Up @@ -96,21 +57,20 @@ func TestIDMSGenerator(t *testing.T) {

t.Run("Testing IDMSGenerator - Disk to Mirror : should pass", func(t *testing.T) {
cr := &ClusterResourcesGenerator{
Log: log,
Config: cfgd2m,
Opts: d2mOpts,
Log: log,
WorkingDir: workingDir,
}
err := cr.IDMSGenerator(ctx, imageList, d2mOpts)
err := cr.IDMSGenerator(imageList)
if err != nil {
t.Fatalf("should not fail")
}

_, err = os.Stat(filepath.Join(d2mOpts.Global.WorkingDir, clusterResourcesDir))
_, err = os.Stat(filepath.Join(workingDir, clusterResourcesDir))
if err != nil {
t.Fatalf("output folder should exist")
}

idmsFiles, err := os.ReadDir(filepath.Join(d2mOpts.Global.WorkingDir, clusterResourcesDir))
idmsFiles, err := os.ReadDir(filepath.Join(workingDir, clusterResourcesDir))
if err != nil {
t.Fatalf("ls output folder should not fail")
}
Expand Down Expand Up @@ -191,3 +151,55 @@ func TestGenerateImageMirrors(t *testing.T) {
}
})
}

func TestUpdateServiceGenerator(t *testing.T) {
log := clog.New("trace")

tmpDir := t.TempDir()
workingDir := tmpDir + "/working-dir"

releaseImage := "quay.io/openshift-release-dev/ocp-release:4.13.10-x86_64"
graphImage := "localhost:5000/openshift/graph-image:latest"

t.Run("Testing IDMSGenerator - Disk to Mirror : should pass", func(t *testing.T) {
cr := &ClusterResourcesGenerator{
Log: log,
WorkingDir: workingDir,
}
err := cr.UpdateServiceGenerator(graphImage, releaseImage)
if err != nil {
t.Fatalf("should not fail")
}

_, err = os.Stat(filepath.Join(workingDir, clusterResourcesDir))
if err != nil {
t.Fatalf("output folder should exist")
}

resourceFiles, err := os.ReadDir(filepath.Join(workingDir, clusterResourcesDir))
if err != nil {
t.Fatalf("ls output folder should not fail")
}

if len(resourceFiles) != 1 {
t.Fatalf("output folder should contain 1 updateservice.yaml file")
}

assert.Equal(t, updateServiceFilename, resourceFiles[0].Name())

// Read the contents of resourceFiles[0]
filePath := filepath.Join(workingDir, clusterResourcesDir, resourceFiles[0].Name())
fileContents, err := os.ReadFile(filePath)
if err != nil {
t.Fatalf("failed to read file: %v", err)
}
actualOSUS := updateservicev1.UpdateService{}
err = yaml.Unmarshal(fileContents, &actualOSUS)
if err != nil {
t.Fatalf("failed to unmarshall file: %v", err)
}

assert.Equal(t, graphImage, actualOSUS.Spec.GraphDataImage)
assert.Equal(t, "quay.io/openshift-release-dev/ocp-release", actualOSUS.Spec.Releases)
})
}
8 changes: 8 additions & 0 deletions v2/pkg/clusterresources/const.go
@@ -0,0 +1,8 @@
package clusterresources

const (
clusterResourcesDir string = "cluster-resources"
updateServiceFilename string = "updateService"
updateServiceResourceName string = "update-service-oc-mirror"
updateServiceResourceKind string = "UpdateService"
)
6 changes: 2 additions & 4 deletions v2/pkg/clusterresources/interface.go
@@ -1,12 +1,10 @@
package clusterresources

import (
"context"

"github.com/openshift/oc-mirror/v2/pkg/api/v1alpha3"
"github.com/openshift/oc-mirror/v2/pkg/mirror"
)

type GeneratorInterface interface {
IDMSGenerator(ctx context.Context, allRelatedImages []v1alpha3.CopyImageSchema, opts mirror.CopyOptions) error
IDMSGenerator(allRelatedImages []v1alpha3.CopyImageSchema) error
UpdateServiceGenerator(graphImage, releaseImage string) error
}
13 changes: 13 additions & 0 deletions v2/pkg/clusterresources/updateservice/v1/groupversion_info.go
@@ -0,0 +1,13 @@
// Copied from https://github.com/openshift/cincinnati-operator/tree/master/api/v1
// The last release v1.0.3 doesn't even contain the API
// Commit : 425be2fc0ec501bfcf9bdb15f75df9d8a7b5ba6c
package v1

import (
"k8s.io/apimachinery/pkg/runtime/schema"
)

var (
// GroupVersion is group version used to register these objects
GroupVersion = schema.GroupVersion{Group: "updateservice.operator.openshift.io", Version: "v1"}
)

0 comments on commit 2311da0

Please sign in to comment.