diff --git a/config/samples/example-test.sh b/config/samples/example-test.sh index 8b728b0d..6caf0f19 100755 --- a/config/samples/example-test.sh +++ b/config/samples/example-test.sh @@ -473,7 +473,9 @@ kubectl apply -f config/samples/core_v1alpha1_repository_grafana_image_repo_over waitComponentStatus "kubebb-system" "repository-grafana-sample-image.grafana" "false" info "4.2 create grafana subscription" -kubectl apply -f config/samples/core_v1alpha1_grafana_subscription.yaml +kubectl apply -f config/samples/core_v1alpha1_grafana_subscription.yaml --dry-run=client -o json | jq '.spec.componentPlanInstallMethod="manual"' | kubectl apply -f - +sleep 10 +kubectl patch subscription -n kubebb-system grafana-sample --type='json' -p='[{"op": "replace", "path": "/spec/componentPlanInstallMethod", "value": "auto"}]' getPodImage "kubebb-system" "app.kubernetes.io/instance=grafana-sample,app.kubernetes.io/name=grafana" "192.168.1.1:5000/grafana-local/grafana" getHelmRevision "kubebb-system" "grafana-sample" "1" kubectl delete -f config/samples/core_v1alpha1_grafana_subscription.yaml diff --git a/controllers/subscription_controller.go b/controllers/subscription_controller.go index e06ccf28..3578fb18 100644 --- a/controllers/subscription_controller.go +++ b/controllers/subscription_controller.go @@ -33,6 +33,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/log" @@ -134,11 +135,19 @@ func (r *SubscriptionReconciler) Reconcile(ctx context.Context, req ctrl.Request return ctrl.Result{}, r.PatchCondition(ctx, sub, corev1alpha1.SubscriptionReconcileSuccess(corev1alpha1.SubscriptionTypeReady).WithMessage(msg)) } logger.V(1).Info("get component latest fetch version") + plan := &corev1alpha1.ComponentPlan{} + var latestPlanApproved *bool if plans := sub.Status.Installed; len(plans) > 0 { - latestVersionInstalled = plans[0].InstalledVersion + latestPlan := plans[0] + latestVersionInstalled = latestPlan.InstalledVersion + if err = r.Get(ctx, types.NamespacedName{Namespace: latestPlan.ComponentPlanRef.Namespace, Name: latestPlan.ComponentPlanRef.Name}, plan); err == nil { + latestPlanApproved = &plan.Spec.Approved + } } logger.V(1).Info("get component latest installed version") - if latestVersionFetch.Equal(&latestVersionInstalled) { + logger.Info(fmt.Sprintf("!!!! latestVersionFetch: %#v, lastestVersionInstalled: %#v, latestPlanApproved: %#v, sub.Spec.ComponentPlanInstallMethod.IsAuto(): %#v", latestVersionFetch, latestVersionInstalled, latestPlanApproved, sub.Spec.ComponentPlanInstallMethod.IsAuto())) + // If component's the latest version is the same as installed and sub's approved is same with the latest plan, skip + if latestVersionFetch.Equal(&latestVersionInstalled) && (latestPlanApproved != nil && sub.Spec.ComponentPlanInstallMethod.IsAuto() == *latestPlanApproved) { msg := "component latest version is the same as installed, skip" logger.Info(msg) return ctrl.Result{}, r.PatchCondition(ctx, sub, corev1alpha1.SubscriptionReconcileSuccess(corev1alpha1.SubscriptionTypeReady).WithMessage(msg)) @@ -178,14 +187,14 @@ func (r *SubscriptionReconciler) Reconcile(ctx context.Context, req ctrl.Request } } } - // create componentplan + // create or update componentplan componentPlanName := corev1alpha1.GenerateComponentPlanName(sub, latestVersionFetch.Version) - if err = r.CreateComponentPlan(ctx, sub, latestVersionFetch); err != nil { - logger.Error(err, "Failed to create component plan") - r.Recorder.Eventf(sub, corev1.EventTypeWarning, "Fail", "failed to create componentPlan %s with error: %s", componentPlanName, err) + if err = r.CreateOrUpdateComponentPlan(ctx, sub, latestVersionFetch); err != nil { + logger.Error(err, "Failed to create or update component plan") + r.Recorder.Eventf(sub, corev1.EventTypeWarning, "Fail", "failed to create or update componentPlan %s with error: %s", componentPlanName, err) return ctrl.Result{Requeue: true, RequeueAfter: 3 * time.Second}, r.PatchCondition(ctx, sub, corev1alpha1.SubscriptionReconcileError(corev1alpha1.SubscriptionTypePlanSynce, err)) } - r.Recorder.Eventf(sub, corev1.EventTypeNormal, "Success", "componentPlan %s create successfully", componentPlanName) + r.Recorder.Eventf(sub, corev1.EventTypeNormal, "Success", "componentPlan %s create or update successfully", componentPlanName) logger.V(1).Info("create component plan") // update status.Installed @@ -295,23 +304,22 @@ func (r *SubscriptionReconciler) UpdateStatusRepositoryHealth(ctx context.Contex return nil } -// CreateComponentPlan create component plan if not exists or update component plan if exists -func (r *SubscriptionReconciler) CreateComponentPlan(ctx context.Context, sub *corev1alpha1.Subscription, fetch corev1alpha1.ComponentVersion) error { +// CreateOrUpdateComponentPlan create component plan if not exists or update component plan if exists +func (r *SubscriptionReconciler) CreateOrUpdateComponentPlan(ctx context.Context, sub *corev1alpha1.Subscription, fetch corev1alpha1.ComponentVersion) (err error) { plan := &corev1alpha1.ComponentPlan{} metav1.SetMetaDataLabel(&plan.ObjectMeta, corev1alpha1.SubscriptionNameLabel, sub.Name) plan.Name = corev1alpha1.GenerateComponentPlanName(sub, fetch.Version) plan.Namespace = sub.Namespace - if err := r.Get(ctx, types.NamespacedName{Namespace: plan.Namespace, Name: plan.Name}, plan); err == nil { - // already exists - return nil - } plan.Spec.Config = sub.Spec.Config plan.Spec.ComponentRef = sub.Spec.ComponentRef plan.Spec.InstallVersion = fetch.Version if sub.Spec.ComponentPlanInstallMethod.IsAuto() { plan.Spec.Approved = true } - return r.Create(ctx, plan) + _, err = controllerutil.CreateOrUpdate(ctx, r.Client, plan, func() error { + return nil + }) + return err } // UpdateStatusInstalled update subscription status installed