-
Notifications
You must be signed in to change notification settings - Fork 1.8k
[run bundle] Install plan generation and approval for subscription #3838
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
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 |
|---|---|---|
|
|
@@ -26,6 +26,7 @@ import ( | |
| log "github.com/sirupsen/logrus" | ||
| "k8s.io/apimachinery/pkg/types" | ||
| "k8s.io/apimachinery/pkg/util/wait" | ||
| "k8s.io/client-go/util/retry" | ||
| "sigs.k8s.io/controller-runtime/pkg/client" | ||
|
|
||
| olmclient "github.com/operator-framework/operator-sdk/internal/olm/client" | ||
|
|
@@ -73,16 +74,20 @@ func (o OperatorInstaller) InstallOperator(ctx context.Context) (*v1alpha1.Clust | |
| return nil, err | ||
| } | ||
|
|
||
| var subscription *v1alpha1.Subscription | ||
| // Create Subscription | ||
| if err = o.createSubscription(ctx, cs); err != nil { | ||
| if subscription, err = o.createSubscription(ctx, cs); err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| // Approve Install Plan (if necessary) | ||
| if approver, ok := o.CatalogCreator.(InstallPlanApprover); ok { | ||
| if err = approver.Approve(ctx, o.PackageName); err != nil { | ||
| return nil, err | ||
| } | ||
| // Wait for the Install Plan to be generated | ||
| if err = o.waitForInstallPlan(ctx, subscription); err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| // Approve Install Plan for the subscription | ||
| if err = o.approveInstallPlan(ctx, subscription); err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| // Wait for successfully installed CSV | ||
|
|
@@ -191,15 +196,17 @@ func (o OperatorInstaller) getOperatorGroup(ctx context.Context) (*v1.OperatorGr | |
| return &ogList.Items[0], true, nil | ||
| } | ||
|
|
||
| func (o OperatorInstaller) createSubscription(ctx context.Context, cs *v1alpha1.CatalogSource) error { | ||
| func (o OperatorInstaller) createSubscription(ctx context.Context, cs *v1alpha1.CatalogSource) (*v1alpha1.Subscription, error) { | ||
| sub := newSubscription(o.StartingCSV, o.cfg.Namespace, | ||
| withPackageChannel(o.PackageName, o.Channel, o.StartingCSV), | ||
| withCatalogSource(cs.GetName(), o.cfg.Namespace)) | ||
| withCatalogSource(cs.GetName(), o.cfg.Namespace), | ||
| withInstallPlanApproval(v1alpha1.ApprovalManual)) | ||
|
|
||
| log.Info("Creating Subscription") | ||
| if err := o.cfg.Client.Create(ctx, sub); err != nil { | ||
| return fmt.Errorf("error creating OperatorGroup: %w", err) | ||
| return nil, fmt.Errorf("error creating subscription: %w", err) | ||
| } | ||
| return nil | ||
| return sub, nil | ||
| } | ||
|
|
||
| func (o OperatorInstaller) getInstalledCSV(ctx context.Context) (*v1alpha1.ClusterServiceVersion, error) { | ||
|
|
@@ -226,3 +233,53 @@ func (o OperatorInstaller) getInstalledCSV(ctx context.Context) (*v1alpha1.Clust | |
| } | ||
| return csv, nil | ||
| } | ||
|
|
||
| // approveInstallPlan approves the install plan for a subscription, which will | ||
| // generate a CSV | ||
| func (o OperatorInstaller) approveInstallPlan(ctx context.Context, sub *v1alpha1.Subscription) error { | ||
| ip := v1alpha1.InstallPlan{} | ||
|
|
||
| ipKey := types.NamespacedName{ | ||
| Name: sub.Status.InstallPlanRef.Name, | ||
| Namespace: sub.Status.InstallPlanRef.Namespace, | ||
| } | ||
|
|
||
| if err := retry.RetryOnConflict(retry.DefaultBackoff, func() error { | ||
| if err := o.cfg.Client.Get(ctx, ipKey, &ip); err != nil { | ||
| return fmt.Errorf("error in getting install plan: %v", err) | ||
| } | ||
| // approve the install plan by setting Approved to true | ||
| ip.Spec.Approved = true | ||
| if err := o.cfg.Client.Update(ctx, &ip); err != nil { | ||
| return fmt.Errorf("error in approving install plan: %v", err) | ||
| } | ||
| return nil | ||
| }); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| // waitForInstallPlan verifies if an Install Plan exists through subscription status | ||
| func (o OperatorInstaller) waitForInstallPlan(ctx context.Context, sub *v1alpha1.Subscription) error { | ||
| subKey := types.NamespacedName{ | ||
| Namespace: sub.GetNamespace(), | ||
| Name: sub.GetName(), | ||
| } | ||
|
|
||
| ipCheck := wait.ConditionFunc(func() (done bool, err error) { | ||
| if err := o.cfg.Client.Get(ctx, subKey, sub); err != nil { | ||
| return false, err | ||
| } | ||
| if sub.Status.InstallPlanRef != nil { | ||
| return true, nil | ||
| } | ||
| return false, nil | ||
| }) | ||
|
|
||
| if err := wait.PollImmediateUntil(200*time.Millisecond, ipCheck, ctx.Done()); err != nil { | ||
| return fmt.Errorf("install plan is not available for the subscription %s: %v", sub.Name, err) | ||
| } | ||
| return nil | ||
| } | ||
|
Member
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. Non-blocking: In one of these install plan functions, do we need to do a sanity check and ensure the install plan is for the CSV that we created in the subscription. In the case of an upgrade being available, there can be multiple install plans and I think the subscription may reference the next available. It may not be strictly necessary based in this case since we would need to approve the initial install plan to do the initial install and let OLM get to the point of doing an upgrade, BUT if it's a simple extra sanity check, it may be a good idea to go ahead and add.
Member
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. Great idea! I guess we can add the below check: I will do this in a follow-up as this is non-blocking. |
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if CI will pass because
InstallPlans created byrun packagemanifestswill not be approved. IIRC we discussed that automatic approval is a bug inrun packagemanifestssince a version is specified but that version might not be the channel head specified in aSubscription, and setting approval to manual is correct for both the index and configmapCatalogCreator's; we would need to approve allSubscriptions manually with this change.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After the catalog source is created, the logic should be identical between
run packagemanifestsandrun bundle.We shouldn't have different implementations of the
InstallPlanApproverinterface (and we probably don't need that interface at all).