diff --git a/.golangci.yml b/.golangci.yml index f5455f0d..4891b55e 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -32,6 +32,7 @@ linters-settings: - github.com/onsi/ginkgo/v2 - github.com/openshift-kni/eco-gosystem/tests/internal/inittools - github.com/openshift-kni/eco-gosystem/tests/ran-du/internal/randuinittools + - github.com/openshift-kni/eco-gosystem/tests/imagebasedupgrade/internal/imagebasedupgradeinittools # Select the Go version to target. The default is '1.13'. go: "1.19" # https://staticcheck.io/docs/options#checks @@ -117,6 +118,10 @@ issues: linters: - gochecknoinits + - path: 'tests/imagebasedupgrade/internal/imagebasedupgradeinittools' + linters: + - gochecknoinits + - path: "tests/.*/tests/.*" linters: - depguard diff --git a/tests/imagebasedupgrade/imagebasedupgrade_suite_test.go b/tests/imagebasedupgrade/imagebasedupgrade_suite_test.go new file mode 100644 index 00000000..88be5b1b --- /dev/null +++ b/tests/imagebasedupgrade/imagebasedupgrade_suite_test.go @@ -0,0 +1,14 @@ +package imagebasedupgrade_test + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + _ "github.com/openshift-kni/eco-gosystem/tests/imagebasedupgrade/tests" +) + +func TestImageBasedUpgrade(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "ImageBasedUpgrade Suite") +} diff --git a/tests/imagebasedupgrade/internal/imagebasedupgradeinittools/imagebasedupgradeinittools.go b/tests/imagebasedupgrade/internal/imagebasedupgradeinittools/imagebasedupgradeinittools.go new file mode 100644 index 00000000..c11fb01d --- /dev/null +++ b/tests/imagebasedupgrade/internal/imagebasedupgradeinittools/imagebasedupgradeinittools.go @@ -0,0 +1,49 @@ +package imagebasedupgradeinittools + +import ( + "os" + + "github.com/golang/glog" + "github.com/openshift-kni/eco-goinfra/pkg/clients" + "github.com/openshift-kni/eco-gosystem/tests/imagebasedupgrade/internal/imagebasedupgradeparams" + "github.com/openshift-kni/eco-gosystem/tests/internal/inittools" +) + +var ( + // SeedHubAPIClient is the api client to the hub cluster. + SeedHubAPIClient *clients.Settings + // TargetHubAPIClient is the api client to the hub cluster. + TargetHubAPIClient *clients.Settings + // SeedSNOAPIClient is the api client to the seed SNO cluster. + SeedSNOAPIClient *clients.Settings + // TargetSNOAPIClient is the api client to the target SNO cluster. + TargetSNOAPIClient *clients.Settings +) + +// init loads all variables automatically when this package is imported. Once package is imported a user has full +// access to all vars within init function. It is recommended to import this package using dot import. +func init() { + SeedHubAPIClient = inittools.APIClient + TargetHubAPIClient = inittools.APIClient + SeedSNOAPIClient = DefineAPIClient(imagebasedupgradeparams.SeedSNOKubeEnvKey) + TargetSNOAPIClient = DefineAPIClient(imagebasedupgradeparams.TargetSNOKubeEnvKey) +} + +// DefineAPIClient creates new api client instance connected to given cluster. +func DefineAPIClient(kubeconfigEnvVar string) *clients.Settings { + kubeFilePath, present := os.LookupEnv(kubeconfigEnvVar) + if !present { + glog.Fatalf("can not load api client. Please check %s env var", kubeconfigEnvVar) + + return nil + } + + client := clients.New(kubeFilePath) + if client == nil { + glog.Fatalf("client is not set please check %s env variable", kubeconfigEnvVar) + + return nil + } + + return client +} diff --git a/tests/imagebasedupgrade/internal/imagebasedupgradeparams/const.go b/tests/imagebasedupgrade/internal/imagebasedupgradeparams/const.go new file mode 100644 index 00000000..4ecbc57d --- /dev/null +++ b/tests/imagebasedupgrade/internal/imagebasedupgradeparams/const.go @@ -0,0 +1,16 @@ +package imagebasedupgradeparams + +const ( + // SeedHubKubeEnvKey is the hub's kubeconfig env var. + SeedHubKubeEnvKey string = "KUBECONFIG_SEED_HUB" + // TargetHubKubeEnvKey is the hub's kubeconfig env var. + TargetHubKubeEnvKey string = "KUBECONFIG_TARGET_HUB" + // SeedSNOKubeEnvKey is the seed kubeconfig env var. + SeedSNOKubeEnvKey string = "KUBECONFIG_SEED_SNO" + // TargetSNOKubeEnvKey is the target kubeconfig env var. + TargetSNOKubeEnvKey string = "KUBECONFIG_TARGET_SNO" + // ImagebasedupgradeCrName is the Imagebasedupgrade CR name. + ImagebasedupgradeCrName string = "upgrade" + // ImagebasedupgradeCrNamespace is the Imagebasedupgrade CR namespace. + ImagebasedupgradeCrNamespace string = "openshift-lifecycle-agent" +) diff --git a/tests/imagebasedupgrade/tests/happy-path-upgrade.go b/tests/imagebasedupgrade/tests/happy-path-upgrade.go new file mode 100644 index 00000000..88ad9f8e --- /dev/null +++ b/tests/imagebasedupgrade/tests/happy-path-upgrade.go @@ -0,0 +1,55 @@ +package tests + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/openshift-kni/eco-goinfra/pkg/lca" + "github.com/openshift-kni/eco-goinfra/pkg/polarion" + "github.com/openshift-kni/eco-gosystem/tests/imagebasedupgrade/internal/imagebasedupgradeinittools" + "github.com/openshift-kni/eco-gosystem/tests/imagebasedupgrade/internal/imagebasedupgradeparams" +) + +// IbuCr is a dedicated var to use and act on it. +var IbuCr = lca.NewImageBasedUpgradeBuilder( + imagebasedupgradeinittools.TargetSNOAPIClient, imagebasedupgradeparams.ImagebasedupgradeCrName) + +var _ = Describe( + "HappyPathUpgrade", + Ordered, + ContinueOnFailure, + Label("HappyPathUpgrade"), func() { + BeforeAll(func() { + By("Generating seed image", func() { + // Test Automation Code Implementation is to be done. + }) + }) + + AfterAll(func() { + // Rollback to pre-upgrade state and reset PolicyGenTemplate. + }) + + It("End to end upgrade happy path", polarion.ID("68954"), Label("HappyPathUpgrade"), func() { + + By("Checking ImageBasedUpgrade CR exists with Idle stage in Target SNO", func() { + crExists := IbuCr.Exists() + Expect(crExists).To(BeTrue()) + }) + + By("Updating ImageBasedUpgrade CR with Prep stage in Target SNO", func() { + IbuCr.WithStage("Prep") + }) + + By("Updating ImageBasedUpgrade CR with Upgrade stage in Target SNO", func() { + IbuCr.WithStage("Upgrade") + }) + + By(" Verifying target SNO cluster ACM registration post upgrade", func() { + + }) + + By("Updating ImageBasedUpgrade CR with Idle stage in Target SNO", func() { + IbuCr.WithStage("Idle") + + }) + }) + }) diff --git a/vendor/github.com/openshift-kni/eco-goinfra/pkg/lca/imagebasedupgrade.go b/vendor/github.com/openshift-kni/eco-goinfra/pkg/lca/imagebasedupgrade.go new file mode 100644 index 00000000..640e3f1b --- /dev/null +++ b/vendor/github.com/openshift-kni/eco-goinfra/pkg/lca/imagebasedupgrade.go @@ -0,0 +1,353 @@ +package lca + +import ( + "context" + "time" + + goclient "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/golang/glog" + + "fmt" + + "github.com/openshift-kni/eco-goinfra/pkg/clients" + "github.com/openshift-kni/eco-goinfra/pkg/msg" + lcav1alpha1 "github.com/openshift-kni/lifecycle-agent/api/v1alpha1" + + k8serrors "k8s.io/apimachinery/pkg/api/errors" + metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" +) + +const ( + isTrue = "True" + isFalse = "False" + isComplete = "Completed" +) + +// ImageBasedUpgradeBuilder provides struct for the imagebasedupgrade object containing connection to +// the cluster and the imagebasedupgrade definitions. +type ImageBasedUpgradeBuilder struct { + // ImageBasedUpgrade definition. Used to store the imagebasedupgrade object. + Definition *lcav1alpha1.ImageBasedUpgrade + + // Created imagebasedupgrade object. + Object *lcav1alpha1.ImageBasedUpgrade + // Used in functions that define or mutate the imagebasedupgrade definition. + // errorMsg is processed before the imagebasedupgrade object is created + errorMsg string + apiClient *clients.Settings +} + +// AdditionalOptions additional options for imagebasedupgrade object. +type AdditionalOptions func(builder *ImageBasedUpgradeBuilder) (*ImageBasedUpgradeBuilder, error) + +// NewImageBasedUpgradeBuilder creates a new instance of ImageBasedUpgrade. +func NewImageBasedUpgradeBuilder( + apiClient *clients.Settings, + name string, +) *ImageBasedUpgradeBuilder { + builder := ImageBasedUpgradeBuilder{ + apiClient: apiClient, + Definition: &lcav1alpha1.ImageBasedUpgrade{ + ObjectMeta: metaV1.ObjectMeta{ + Name: name, + }, + }, + } + + if name == "" { + glog.V(100).Infof("The name of the imagebasedupgrade is empty") + + builder.errorMsg = "ImageBasedUpgrade name cannot be empty" + } + + return &builder +} + +// WithOptions creates imagebasedupgrade with generic mutation options. +func (builder *ImageBasedUpgradeBuilder) WithOptions(options ...AdditionalOptions) *ImageBasedUpgradeBuilder { + if valid, _ := builder.validate(); !valid { + return builder + } + + glog.V(100).Infof("Setting imagebasedupgrade additional options") + + for _, option := range options { + if option != nil { + builder, err := option(builder) + + if err != nil { + glog.V(100).Infof("Error occurred in mutation function") + + builder.errorMsg = err.Error() + + return builder + } + } + } + + return builder +} + +// PullImageBasedUpgrade pulls existing imagebasedupgrade from cluster. +func PullImageBasedUpgrade(apiClient *clients.Settings, name string) (*ImageBasedUpgradeBuilder, error) { + glog.V(100).Infof("Pulling existing imagebasedupgrade name %s from cluster", name) + + builder := ImageBasedUpgradeBuilder{ + apiClient: apiClient, + Definition: &lcav1alpha1.ImageBasedUpgrade{ + ObjectMeta: metaV1.ObjectMeta{ + Name: name, + }, + }, + } + + if name == "" { + glog.V(100).Infof("The name of the imagebasedupgrade is empty") + + builder.errorMsg = "imagebasedupgrade 'name' cannot be empty" + } + + if !builder.Exists() { + return nil, fmt.Errorf("imagebasedupgrade object %s doesn't exist", name) + } + + builder.Definition = builder.Object + + return &builder, nil +} + +// Update modifies the imagebasedupgrade resource on the cluster +// to match what is defined in the local definition of the builder. +func (builder *ImageBasedUpgradeBuilder) Update() (*ImageBasedUpgradeBuilder, error) { + if valid, err := builder.validate(); !valid { + return builder, err + } + + glog.V(100).Infof("Updating imagebasedupgrade %s", + builder.Definition.Name) + + if !builder.Exists() { + glog.V(100).Infof("imagebasedupgrade %s does not exist", + builder.Definition.Name) + + builder.errorMsg = "Unable to update non-existing imagebasedupgrade" + } + + if builder.errorMsg != "" { + return nil, fmt.Errorf(builder.errorMsg) + } + + err := builder.apiClient.Update(context.TODO(), builder.Definition) + if err == nil { + builder.Object = builder.Definition + } + + return builder, err +} + +// Delete removes the existing imagebasedupgrade from a cluster. +// Note that a new imagebasedupgrade with the specs from the deleted +// one is created instantly upon deletion. +func (builder *ImageBasedUpgradeBuilder) Delete() (*ImageBasedUpgradeBuilder, error) { + if valid, err := builder.validate(); !valid { + return builder, err + } + + glog.V(100).Infof("Deleting the imagebasedupgrade %s", + builder.Definition.Name) + + if !builder.Exists() { + return builder, fmt.Errorf("imagebasedupgrade cannot be deleted because it does not exist") + } + + err := builder.apiClient.Delete(context.TODO(), builder.Definition) + + if err != nil { + return builder, fmt.Errorf("can not delete imagebasedupgrade: %w", err) + } + + builder.Object = nil + + return builder, nil +} + +// Get returns imagebasedupgrade object if found. +func (builder *ImageBasedUpgradeBuilder) Get() (*lcav1alpha1.ImageBasedUpgrade, error) { + if valid, err := builder.validate(); !valid { + return nil, err + } + + glog.V(100).Infof("Getting imagebasedupgrade %s", + builder.Definition.Name) + + imagebasedupgrade := &lcav1alpha1.ImageBasedUpgrade{} + err := builder.apiClient.Get(context.TODO(), goclient.ObjectKey{ + Name: builder.Definition.Name, + }, imagebasedupgrade) + + if err != nil { + return nil, err + } + + return imagebasedupgrade, err +} + +// Exists checks whether the given imagebasedupgrade exists. +func (builder *ImageBasedUpgradeBuilder) Exists() bool { + if valid, _ := builder.validate(); !valid { + return false + } + + glog.V(100).Infof("Checking if imagebasedupgrade %s", + builder.Definition.Name) + + var err error + builder.Object, err = builder.Get() + + return err == nil || !k8serrors.IsNotFound(err) +} + +// WithSeedImage sets the seed image used by the imagebasedupgrade. +func (builder *ImageBasedUpgradeBuilder) WithSeedImage( + seedImage string) *ImageBasedUpgradeBuilder { + if valid, _ := builder.validate(); !valid { + return builder + } + + glog.V(100).Infof("Setting image %s in imagebasedupgrade", seedImage) + + builder.Definition.Spec.SeedImageRef.Image = seedImage + + return builder +} + +// WithSeedImageVersion sets the seed image version used by the imagebasedupgrade. +func (builder *ImageBasedUpgradeBuilder) WithSeedImageVersion( + seedImageVersion string) *ImageBasedUpgradeBuilder { + if valid, _ := builder.validate(); !valid { + return builder + } + + glog.V(100).Infof("Setting seed image version %s in imagebasedupgrade", seedImageVersion) + + builder.Definition.Spec.SeedImageRef.Version = seedImageVersion + + return builder +} + +// WaitUntilStageComplete waits the specified timeout for the imagebasedupgrade to complete +// actions for the provided stage . +func (builder *ImageBasedUpgradeBuilder) WaitUntilStageComplete(stage string) (*ImageBasedUpgradeBuilder, error) { + if valid, err := builder.validate(); !valid { + return builder, err + } + + glog.V(100).Infof("Waiting for imagebasedupgrade %s to set stage %s", + builder.Definition.Name, + stage) + + if !builder.Exists() { + glog.V(100).Infof("The imagebasedupgrade does not exist on the cluster") + + return builder, fmt.Errorf(builder.errorMsg) + } + + // Polls periodically to determine if imagebasedupgrade is in desired state. + var err error + err = wait.PollUntilContextTimeout( + context.TODO(), time.Second*3, time.Minute*30, true, func(ctx context.Context) (bool, error) { + builder.Object, err = builder.Get() + + if err != nil { + return false, nil + } + + for _, condition := range builder.Object.Status.Conditions { + switch stage { + case "Idle": + if condition.Status == isTrue && condition.Type == "Idle" { + return true, nil + } + + case "Prep": + if condition.Status == isFalse && condition.Type == "PrepInProgress" && + condition.Message == "Prep completed" && condition.Reason == isComplete { + return true, nil + + } + case "Upgrade": + if condition.Status == isFalse && condition.Type == "UpgradeInProgress" && + condition.Message == "Upgrade completed" && condition.Reason == isComplete { + return true, nil + } + + case "Rollback": + if condition.Status == isFalse && condition.Type == "RollbackInProgress" && + condition.Message == "Rollback completed" && condition.Reason == isComplete { + return true, nil + } + + default: + return false, fmt.Errorf("wrong stage selected for imagebasedupgrade") + + } + + } + + return false, nil + + }) + + if err == nil { + return builder, nil + } + + return nil, err +} + +// WithStage sets the stage used by the imagebasedupgrade. +func (builder *ImageBasedUpgradeBuilder) WithStage( + stage string) *ImageBasedUpgradeBuilder { + if valid, _ := builder.validate(); !valid { + return builder + } + + glog.V(100).Infof("Setting stage %s in imagebasedupgrade", stage) + builder.Definition.Spec.Stage = lcav1alpha1.ImageBasedUpgradeStage(stage) + + return builder +} + +// validate will check that the builder and builder definition are properly initialized before +// accessing any member fields. +func (builder *ImageBasedUpgradeBuilder) validate() (bool, error) { + resourceCRD := "ImageBasedUpgrade" + + if builder == nil { + glog.V(100).Infof("The %s builder is uninitialized", resourceCRD) + + return false, fmt.Errorf("error: received nil %s builder", resourceCRD) + } + + if builder.Definition == nil { + glog.V(100).Infof("The %s is undefined", resourceCRD) + + builder.errorMsg = msg.UndefinedCrdObjectErrString(resourceCRD) + } + + if builder.apiClient == nil { + glog.V(100).Infof("The %s builder apiclient is nil", resourceCRD) + + builder.errorMsg = fmt.Sprintf("%s builder cannot have nil apiClient", resourceCRD) + } + + if builder.errorMsg != "" { + glog.V(100).Infof("The %s builder has error message: %s", resourceCRD, builder.errorMsg) + + return false, fmt.Errorf(builder.errorMsg) + } + + return true, nil +} diff --git a/vendor/github.com/openshift-kni/eco-goinfra/pkg/lca/seedgenerator.go b/vendor/github.com/openshift-kni/eco-goinfra/pkg/lca/seedgenerator.go new file mode 100644 index 00000000..e2576659 --- /dev/null +++ b/vendor/github.com/openshift-kni/eco-goinfra/pkg/lca/seedgenerator.go @@ -0,0 +1,294 @@ +package lca + +import ( + "context" + "fmt" + "time" + + "github.com/golang/glog" + "github.com/openshift-kni/eco-goinfra/pkg/clients" + "github.com/openshift-kni/eco-goinfra/pkg/msg" + lcasgv1alpha1 "github.com/openshift-kni/lifecycle-agent/api/seedgenerator/v1alpha1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + goclient "sigs.k8s.io/controller-runtime/pkg/client" +) + +// SeedGenerator provides struct for the seedgenerator object containing connection to +// the cluster and the seedgenerator definitions. +type SeedGeneratorBuilder struct { + // SeedGenerator definition. Used to store the seedgenerator object. + Definition *lcasgv1alpha1.SeedGenerator + // Created seedgenerator object. + Object *lcasgv1alpha1.SeedGenerator + // Used in functions that define or mutate the seedgenerator definition. + // errorMsg is processed before the seedgenerator object is created + errorMsg string + apiClient *clients.Settings +} + +// SeedGeneratorAdditionalOptions additional options for imagebasedupgrade object. +type SeedGeneratorAdditionalOptions func(builder *SeedGeneratorBuilder) (*SeedGeneratorBuilder, error) + +// NewBuilder creates a new instance of SeedGenerator. +func NewSeedGeneratorBuilder( + apiClient *clients.Settings, + name string, +) *SeedGeneratorBuilder { + builder := SeedGeneratorBuilder{ + apiClient: apiClient, + Definition: &lcasgv1alpha1.SeedGenerator{ + ObjectMeta: metaV1.ObjectMeta{ + Name: name, + }, + }, + } + + if name == "" { + glog.V(100).Infof("The name of the seedgenerator is empty") + + builder.errorMsg = "SeedGenerator name cannot be empty" + } + + return &builder +} + +// WithOptions creates seedgenerator with generic mutation options. +func (builder *SeedGeneratorBuilder) WithOptions(options ...SeedGeneratorAdditionalOptions) *SeedGeneratorBuilder { + if valid, _ := builder.validate(); !valid { + return builder + } + + glog.V(100).Infof("Setting seedgenerator additional options") + + for _, option := range options { + if option != nil { + builder, err := option(builder) + + if err != nil { + glog.V(100).Infof("Error occurred in mutation function") + + builder.errorMsg = err.Error() + + return builder + } + } + } + + return builder +} + +// Create makes a seedgenerator in the cluster and stores the created object in struct. +func (builder *SeedGeneratorBuilder) Create() (*SeedGeneratorBuilder, error) { + if valid, err := builder.validate(); !valid { + return builder, err + } + + glog.V(100).Infof("Creating the seedgenerator %s", + builder.Definition.Name) + + var err error + if !builder.Exists() { + err = builder.apiClient.Create(context.TODO(), builder.Definition) + if err == nil { + builder.Object = builder.Definition + } + } + + return builder, err +} + +// PullSeedGenerator pulls existing seedgenerator from cluster. +func PullSeedGenerator(apiClient *clients.Settings, name string) (*SeedGeneratorBuilder, error) { + glog.V(100).Infof("Pulling existing seedgenerator name %s from cluster", name) + + builder := SeedGeneratorBuilder{ + apiClient: apiClient, + Definition: &lcasgv1alpha1.SeedGenerator{ + ObjectMeta: metaV1.ObjectMeta{ + Name: name, + }, + }, + } + + if name == "" { + glog.V(100).Infof("The name of the seedgenerator is empty") + + builder.errorMsg = "seedgenerator 'name' cannot be empty" + } + + if !builder.Exists() { + return nil, fmt.Errorf("seedgenerator object %s doesn't exist", name) + } + + builder.Definition = builder.Object + + return &builder, nil +} + +// Delete removes the existing seedgenerator from a cluster. +func (builder *SeedGeneratorBuilder) Delete() (*SeedGeneratorBuilder, error) { + if valid, err := builder.validate(); !valid { + return builder, err + } + + glog.V(100).Infof("Deleting the seedgenerator %s", + builder.Definition.Name) + + if !builder.Exists() { + return builder, fmt.Errorf("seedgenerator cannot be deleted because it does not exist") + } + + err := builder.apiClient.Delete(context.TODO(), builder.Definition) + + if err != nil { + return builder, fmt.Errorf("can not delete seedgenerator: %w", err) + } + + builder.Object = nil + + return builder, nil +} + +// Get returns seedgenerator object if found. +func (builder *SeedGeneratorBuilder) Get() (*lcasgv1alpha1.SeedGenerator, error) { + if valid, err := builder.validate(); !valid { + return nil, err + } + + glog.V(100).Infof("Getting seedgenerator %s", + builder.Definition.Name) + + seedgenerator := &lcasgv1alpha1.SeedGenerator{} + err := builder.apiClient.Get(context.TODO(), goclient.ObjectKey{ + Name: builder.Definition.Name, + }, seedgenerator) + + if err != nil { + return nil, err + } + + return seedgenerator, err +} + +// Exists checks whether the given seedgenerator exists. +func (builder *SeedGeneratorBuilder) Exists() bool { + if valid, _ := builder.validate(); !valid { + return false + } + + glog.V(100).Infof("Checking if seedgenerator %s exists", + builder.Definition.Name) + + var err error + builder.Object, err = builder.Get() + + return err == nil || !k8serrors.IsNotFound(err) +} + +// WithSeedImage sets the seed image used by the seedgenerator. +func (builder *SeedGeneratorBuilder) WithSeedImage( + seedImage string) *SeedGeneratorBuilder { + if valid, _ := builder.validate(); !valid { + return builder + } + + glog.V(100).Infof("Setting seed image %s in seedgenerator", seedImage) + + builder.Definition.Spec.SeedImage = seedImage + + return builder +} + +// WithRecertImage sets the recert image used by the seedgenerator. +func (builder *SeedGeneratorBuilder) WithRecertImage( + recertImage string) *SeedGeneratorBuilder { + if valid, _ := builder.validate(); !valid { + return builder + } + + glog.V(100).Infof("Setting recert image %s in seedgenerator", recertImage) + + builder.Definition.Spec.RecertImage = recertImage + + return builder +} + +// WaitUntilComplete waits the specified timeout for the seedgenerator to complete +// actions. +func (builder *SeedGeneratorBuilder) WaitUntilComplete(timeout time.Duration) (*SeedGeneratorBuilder, error) { + if valid, err := builder.validate(); !valid { + return builder, err + } + + glog.V(100).Infof("Waiting for seedgenerator %s to complete actions", + builder.Definition.Name) + + if !builder.Exists() { + glog.V(100).Infof("The seedgenerator does not exist on the cluster") + + return builder, fmt.Errorf(builder.errorMsg) + } + + // Polls periodically to determine if seedgenerator is in desired state. + var err error + err = wait.PollUntilContextTimeout( + context.TODO(), time.Second*3, timeout, true, func(ctx context.Context) (bool, error) { + builder.Object, err = builder.Get() + + if err != nil { + return false, nil + } + + for _, condition := range builder.Object.Status.Conditions { + + if condition.Status == "True" && condition.Type == "SeedGenCompleted" && + condition.Reason == "Completed" { + return true, nil + } + + } + + return false, nil + + }) + + if err == nil { + return builder, nil + } + + return nil, err +} + +// validate will check that the builder and builder definition are properly initialized before +// accessing any member fields. +func (builder *SeedGeneratorBuilder) validate() (bool, error) { + resourceCRD := "SeedGenerator" + + if builder == nil { + glog.V(100).Infof("The %s builder is uninitialized", resourceCRD) + + return false, fmt.Errorf("error: received nil %s builder", resourceCRD) + } + + if builder.Definition == nil { + glog.V(100).Infof("The %s is undefined", resourceCRD) + + builder.errorMsg = msg.UndefinedCrdObjectErrString(resourceCRD) + } + + if builder.apiClient == nil { + glog.V(100).Infof("The %s builder apiclient is nil", resourceCRD) + + builder.errorMsg = fmt.Sprintf("%s builder cannot have nil apiClient", resourceCRD) + } + + if builder.errorMsg != "" { + glog.V(100).Infof("The %s builder has error message: %s", resourceCRD, builder.errorMsg) + + return false, fmt.Errorf(builder.errorMsg) + } + + return true, nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index e8dc2008..b6767bdb 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -452,6 +452,7 @@ github.com/openshift-kni/eco-goinfra/pkg/clients github.com/openshift-kni/eco-goinfra/pkg/clusterversion github.com/openshift-kni/eco-goinfra/pkg/daemonset github.com/openshift-kni/eco-goinfra/pkg/deployment +github.com/openshift-kni/eco-goinfra/pkg/lca github.com/openshift-kni/eco-goinfra/pkg/mco github.com/openshift-kni/eco-goinfra/pkg/msg github.com/openshift-kni/eco-goinfra/pkg/nad