Skip to content

Commit

Permalink
managedcluster-controller tests (#830)
Browse files Browse the repository at this point in the history
* managedcluster controller test

Signed-off-by: Artem Bortnikov <[email protected]>

* minor rework

Signed-off-by: Artem Bortnikov <[email protected]>

* rework objects creation in tests

Signed-off-by: Artem Bortnikov <[email protected]>

* fix linting

Signed-off-by: Artem Bortnikov <[email protected]>

* abstract interaction with helm by interface

Signed-off-by: Artem Bortnikov <[email protected]>

* separate tests for dry-run and normal reconciliation

Signed-off-by: Artem Bortnikov <[email protected]>

* enhance clusterdeployment tests

Signed-off-by: Artem Bortnikov <[email protected]>

* update according to review comments

Signed-off-by: Artem Bortnikov <[email protected]>

* fix shadowing ctx declaration

Signed-off-by: Artem Bortnikov <[email protected]>

---------

Signed-off-by: Artem Bortnikov <[email protected]>
  • Loading branch information
BROngineer authored Jan 6, 2025
1 parent c6ade42 commit 0adc43f
Show file tree
Hide file tree
Showing 9 changed files with 639 additions and 163 deletions.
2 changes: 1 addition & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ linters-settings:
- ["call-chain", "loop", "method-call", "recover", "immediate-recover", "return"]
- name: dot-imports
arguments:
- { allowedPackages: ["github.com/onsi/ginkgo/v2","github.com/onsi/gomega"] }
- { allowedPackages: ["github.com/onsi/ginkgo/v2","github.com/onsi/gomega","sigs.k8s.io/controller-runtime/pkg/envtest/komega"] }
- name: duplicated-imports
- name: early-return
- name: empty-block
Expand Down
13 changes: 12 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,10 @@ CAPI_OPERATOR_VERSION ?= v$(shell $(YQ) -r '.dependencies.[] | select(.name == "
CAPI_OPERATOR_CRD_PREFIX ?= "operator.cluster.x-k8s.io_"
CAPI_OPERATOR_CRDS ?= capi-operator-crds

CLUSTER_API_VERSION ?= v1.9.3
CLUSTER_API_CRD_PREFIX ?= "cluster.x-k8s.io_"
CLUSTER_API_CRDS ?= cluster-api-crds

## Tool Binaries
KUBECTL ?= kubectl
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen-$(CONTROLLER_TOOLS_VERSION)
Expand Down Expand Up @@ -511,8 +515,15 @@ $(CAPI_OPERATOR_CRDS): | $(YQ) $(EXTERNAL_CRD_DIR)
curl -s --fail https://raw.githubusercontent.com/kubernetes-sigs/cluster-api-operator/$(CAPI_OPERATOR_VERSION)/config/crd/bases/$(CAPI_OPERATOR_CRD_PREFIX)${name}.yaml \
> $(EXTERNAL_CRD_DIR)/$(CAPI_OPERATOR_CRD_PREFIX)${name}-$(CAPI_OPERATOR_VERSION).yaml;)

$(CLUSTER_API_CRDS): | $(YQ) $(EXTERNAL_CRD_DIR)
rm -f $(EXTERNAL_CRD_DIR)/$(CLUSTER_API_CRD_PREFIX)*
@$(foreach name, \
clusters machinedeployments, \
curl -s --fail https://raw.githubusercontent.com/kubernetes-sigs/cluster-api/$(CLUSTER_API_VERSION)/config/crd/bases/$(CLUSTER_API_CRD_PREFIX)${name}.yaml \
> $(EXTERNAL_CRD_DIR)/$(CLUSTER_API_CRD_PREFIX)${name}-$(CLUSTER_API_VERSION).yaml;)

.PHONY: external-crd
external-crd: $(FLUX_HELM_CRD) $(FLUX_SOURCE_CHART_CRD) $(FLUX_SOURCE_REPO_CRD) $(SVELTOS_CRD) $(CAPI_OPERATOR_CRDS)
external-crd: $(FLUX_HELM_CRD) $(FLUX_SOURCE_CHART_CRD) $(FLUX_SOURCE_REPO_CRD) $(SVELTOS_CRD) $(CAPI_OPERATOR_CRDS) $(CLUSTER_API_CRDS)

.PHONY: kind
kind: $(KIND) ## Download kind locally if necessary.
Expand Down
35 changes: 13 additions & 22 deletions internal/controller/clusterdeployment_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,16 @@ const (
DefaultRequeueInterval = 10 * time.Second
)

type helmActor interface {
DownloadChartFromArtifact(ctx context.Context, artifact *sourcev1.Artifact) (*chart.Chart, error)
InitializeConfiguration(clusterDeployment *hmc.ClusterDeployment, log action.DebugLog) (*action.Configuration, error)
EnsureReleaseWithValues(ctx context.Context, actionConfig *action.Configuration, hcChart *chart.Chart, clusterDeployment *hmc.ClusterDeployment) error
}

// ClusterDeploymentReconciler reconciles a ClusterDeployment object
type ClusterDeploymentReconciler struct {
client.Client
helmActor
Config *rest.Config
DynamicClient *dynamic.DynamicClient
SystemNamespace string
Expand Down Expand Up @@ -128,7 +135,7 @@ func (r *ClusterDeploymentReconciler) setStatusFromChildObjects(ctx context.Cont

if metaCondition.Reason == "" && metaCondition.Status == metav1.ConditionTrue {
metaCondition.Message += " is Ready"
metaCondition.Reason = "Succeeded"
metaCondition.Reason = hmc.SucceededReason
}
apimeta.SetStatusCondition(clusterDeployment.GetConditions(), metaCondition)
}
Expand Down Expand Up @@ -231,7 +238,7 @@ func (r *ClusterDeploymentReconciler) updateCluster(ctx context.Context, mc *hmc
return ctrl.Result{}, err
}
l.Info("Downloading Helm chart")
hcChart, err := helm.DownloadChartFromArtifact(ctx, source.GetArtifact())
hcChart, err := r.DownloadChartFromArtifact(ctx, source.GetArtifact())
if err != nil {
apimeta.SetStatusCondition(mc.GetConditions(), metav1.Condition{
Type: hmc.HelmChartReadyCondition,
Expand All @@ -243,15 +250,13 @@ func (r *ClusterDeploymentReconciler) updateCluster(ctx context.Context, mc *hmc
}

l.Info("Initializing Helm client")
getter := helm.NewMemoryRESTClientGetter(r.Config, r.RESTMapper())
actionConfig := new(action.Configuration)
err = actionConfig.Init(getter, mc.Namespace, "secret", l.Info)
actionConfig, err := r.InitializeConfiguration(mc, l.Info)
if err != nil {
return ctrl.Result{}, err
}

l.Info("Validating Helm chart with provided values")
if err := validateReleaseWithValues(ctx, actionConfig, mc, hcChart); err != nil {
if err = r.EnsureReleaseWithValues(ctx, actionConfig, hcChart, mc); err != nil {
apimeta.SetStatusCondition(mc.GetConditions(), metav1.Condition{
Type: hmc.HelmChartReadyCondition,
Status: metav1.ConditionFalse,
Expand Down Expand Up @@ -492,22 +497,6 @@ func (r *ClusterDeploymentReconciler) updateServices(ctx context.Context, mc *hm
return ctrl.Result{}, nil
}

func validateReleaseWithValues(ctx context.Context, actionConfig *action.Configuration, clusterDeployment *hmc.ClusterDeployment, hcChart *chart.Chart) error {
install := action.NewInstall(actionConfig)
install.DryRun = true
install.ReleaseName = clusterDeployment.Name
install.Namespace = clusterDeployment.Namespace
install.ClientOnly = true

vals, err := clusterDeployment.HelmValues()
if err != nil {
return err
}

_, err = install.RunWithContext(ctx, hcChart, vals)
return err
}

// updateStatus updates the status for the ClusterDeployment object.
func (r *ClusterDeploymentReconciler) updateStatus(ctx context.Context, clusterDeployment *hmc.ClusterDeployment, template *hmc.ClusterTemplate) error {
clusterDeployment.Status.ObservedGeneration = clusterDeployment.Generation
Expand Down Expand Up @@ -854,6 +843,8 @@ func (r *ClusterDeploymentReconciler) setAvailableUpgrades(ctx context.Context,

// SetupWithManager sets up the controller with the Manager.
func (r *ClusterDeploymentReconciler) SetupWithManager(mgr ctrl.Manager) error {
r.helmActor = helm.NewActor(r.Config, r.RESTMapper())

return ctrl.NewControllerManagedBy(mgr).
For(&hmc.ClusterDeployment{}).
Watches(&hcv2.HelmRelease{},
Expand Down
Loading

0 comments on commit 0adc43f

Please sign in to comment.