Skip to content

Commit

Permalink
Merge pull request #24 from Kshatrix/remove-provider-spec
Browse files Browse the repository at this point in the history
Update Template status based on chart metadata
  • Loading branch information
Kshatrix authored Jun 11, 2024
2 parents 21e3d55 + 51bedfa commit 33555ea
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 35 deletions.
41 changes: 36 additions & 5 deletions api/v1alpha1/template_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,35 @@ import (

const (
// TemplateKind is the string representation of a Template.
TemplateKind = "Template"
TemplateKind = "Template"
// DeploymentKind is the string representation of a Deployment.
DeploymentKind = "Deployment"

// ChartAnnotationType is an annotation containing the type of Template.
ChartAnnotationType = "hmc.mirantis.com/type"
// ChartAnnotationInfraProvider is an annotation containing the CAPI provider associated with Template.
ChartAnnotationInfraProvider = "hmc.mirantis.com/infrastructure-provider"
// ChartAnnotationBootstrapProvider is an annotation containing the k8s distribution associated with Template.
ChartAnnotationBootstrapProvider = "hmc.mirantis.com/bootstrap-provider"
)

// TemplateType specifies the type of template packaged as a helm chart.
// Should be provided in the chart Annotations.
type TemplateType string

const (
// TemplateTypeDeployment is the type used for creating HMC Deployment objects
TemplateTypeDeployment TemplateType = "deployment"
// TemplateTypeInfraProvider is the type used for adding CAPI infrastructure providers in the HMC Management object
TemplateTypeInfraProvider TemplateType = "infrastructure-provider"
// TemplateTypeBootstrapProvider is the type used for adding CAPI bootstrap providers in the HMC Management object
TemplateTypeBootstrapProvider TemplateType = "bootstrap-provider"
// TemplateTypeManagement is the type used for HMC management components
TemplateTypeManagement TemplateType = "management"
)

// TemplateSpec defines the desired state of Template
type TemplateSpec struct {
// Provider specifies a CAPI provider associated with the template.
// +kubebuilder:validation:Enum=aws
// +kubebuilder:validation:Required
Provider string `json:"provider"`
// Helm holds a reference to a Helm chart representing the HMC template
// +kubebuilder:validation:Required
Helm HelmSpec `json:"helm"`
Expand Down Expand Up @@ -70,6 +89,18 @@ type TemplateStatus struct {
// Helm chart representing the template.
// +optional
ChartRef *helmcontrollerv2.CrossNamespaceSourceReference `json:"chartRef,omitempty"`
// Type specifies the type of the provided template, as discovered from the Helm chart metadata.
// +kubebuilder:validation:Enum=deployment;infrastructure-provider;bootstrap-provider;management
Type string `json:"type,omitempty"`
// InfrastructureProvider specifies a CAPI infrastructure provider associated with the template.
// +optional
InfrastructureProvider string `json:"infrastructureProvider,omitempty"`
// BootstrapProvider specifies a CAPI bootstrap provider associated with the template.
// +optional
BootstrapProvider string `json:"bootstrapProvider,omitempty"`
// ObservedGeneration is the last observed generation.
// +optional
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
}

type TemplateValidationStatus struct {
Expand Down
28 changes: 21 additions & 7 deletions charts/hmc/templates/template-crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -87,19 +87,16 @@ spec:
- message: either chartName or chartRef must be set
rule: (has(self.chartName) && !has(self.chartRef)) || (!has(self.chartName)
&& has(self.chartRef))
provider:
description: Provider specifies a CAPI provider associated with the
template.
enum:
- aws
type: string
required:
- helm
- provider
type: object
status:
description: TemplateStatus defines the observed state of Template
properties:
bootstrapProvider:
description: BootstrapProvider specifies a CAPI bootstrap provider associated
with the template.
type: string
chartRef:
description: |-
ChartRef is a reference to a source controller resource containing the
Expand Down Expand Up @@ -138,6 +135,23 @@ spec:
description:
description: Descriptions contains information about the template.
type: string
infrastructureProvider:
description: InfrastructureProvider specifies a CAPI infrastructure
provider associated with the template.
type: string
observedGeneration:
description: ObservedGeneration is the last observed generation.
format: int64
type: integer
type:
description: Type specifies the type of the provided template, as discovered
from the Helm chart metadata.
enum:
- deployment
- infrastructure-provider
- bootstrap-provider
- management
type: string
valid:
description: Valid indicates whether the template passed validation
or not.
Expand Down
28 changes: 21 additions & 7 deletions config/crd/bases/hmc.mirantis.com_templates.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -86,19 +86,16 @@ spec:
- message: either chartName or chartRef must be set
rule: (has(self.chartName) && !has(self.chartRef)) || (!has(self.chartName)
&& has(self.chartRef))
provider:
description: Provider specifies a CAPI provider associated with the
template.
enum:
- aws
type: string
required:
- helm
- provider
type: object
status:
description: TemplateStatus defines the observed state of Template
properties:
bootstrapProvider:
description: BootstrapProvider specifies a CAPI bootstrap provider
associated with the template.
type: string
chartRef:
description: |-
ChartRef is a reference to a source controller resource containing the
Expand Down Expand Up @@ -137,6 +134,23 @@ spec:
description:
description: Descriptions contains information about the template.
type: string
infrastructureProvider:
description: InfrastructureProvider specifies a CAPI infrastructure
provider associated with the template.
type: string
observedGeneration:
description: ObservedGeneration is the last observed generation.
format: int64
type: integer
type:
description: Type specifies the type of the provided template, as
discovered from the Helm chart metadata.
enum:
- deployment
- infrastructure-provider
- bootstrap-provider
- management
type: string
valid:
description: Valid indicates whether the template passed validation
or not.
Expand Down
1 change: 0 additions & 1 deletion internal/controller/deployment_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ var _ = Describe("Deployment Controller", func() {
Namespace: "default",
},
Spec: hmc.TemplateSpec{
Provider: "aws",
Helm: hmc.HelmSpec{
ChartRef: &hcv2.CrossNamespaceSourceReference{
Kind: "HelmChart",
Expand Down
72 changes: 58 additions & 14 deletions internal/controller/template_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ import (

v2 "github.com/fluxcd/helm-controller/api/v2"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
"helm.sh/helm/v3/pkg/chart"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/api/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
Expand All @@ -43,6 +44,13 @@ const (
defaultReconcileInterval = 10 * time.Minute
)

var (
errNoInfraProvider = fmt.Errorf("no infra provider specified: %s chart annotation must not be empty", hmc.ChartAnnotationInfraProvider)
errNoBootstrapProvider = fmt.Errorf("no bootstrap provider specified: %s chart annotation must not be empty", hmc.ChartAnnotationBootstrapProvider)
errNoProviderType = fmt.Errorf("template type is not supported: %s chart annotation must be one of [%s/%s/%s]",
hmc.ChartAnnotationType, hmc.TemplateTypeDeployment, hmc.ChartAnnotationInfraProvider, hmc.ChartAnnotationBootstrapProvider)
)

// TemplateReconciler reconciles a Template object
type TemplateReconciler struct {
client.Client
Expand All @@ -63,7 +71,7 @@ func (r *TemplateReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c

template := &hmc.Template{}
if err := r.Get(ctx, req.NamespacedName, template); err != nil {
if errors.IsNotFound(err) {
if apierrors.IsNotFound(err) {
l.Info("Template not found, ignoring since object must be deleted")
return ctrl.Result{}, nil
}
Expand Down Expand Up @@ -100,8 +108,7 @@ func (r *TemplateReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
if err, reportStatus := helmArtifactReady(hcChart); err != nil {
l.Info("HelmChart Artifact is not ready")
if reportStatus {
template.Status.ValidationError = err.Error()
_ = r.updateStatus(ctx, template)
_ = r.updateStatus(ctx, template, err.Error())
}
return ctrl.Result{}, err
}
Expand All @@ -111,15 +118,18 @@ func (r *TemplateReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
if err != nil {
l.Error(err, "Failed to download Helm chart")
err = fmt.Errorf("failed to download chart: %s", err)
template.Status.ValidationError = err.Error()
_ = r.updateStatus(ctx, template)
_ = r.updateStatus(ctx, template, err.Error())
return ctrl.Result{}, err
}
l.Info("Validating Helm chart")
if err := r.parseChartMetadata(template, helmChart); err != nil {
l.Error(err, "Failed to parse Helm chart metadata")
_ = r.updateStatus(ctx, template, err.Error())
return ctrl.Result{}, err
}
if err = helmChart.Validate(); err != nil {
l.Error(err, "Helm chart validation failed")
template.Status.ValidationError = err.Error()
_ = r.updateStatus(ctx, template)
_ = r.updateStatus(ctx, template, err.Error())
return ctrl.Result{}, err
}

Expand All @@ -128,19 +138,53 @@ func (r *TemplateReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
if err != nil {
l.Error(err, "Failed to parse Helm chart values")
err = fmt.Errorf("failed to parse Helm chart values: %s", err)
template.Status.ValidationError = err.Error()
_ = r.updateStatus(ctx, template)
_ = r.updateStatus(ctx, template, err.Error())
return ctrl.Result{}, err
}
template.Status.Config = &apiextensionsv1.JSON{Raw: rawValues}
l.Info("Chart validation completed successfully")
template.Status.Valid = true
template.Status.ValidationError = ""

return ctrl.Result{}, r.updateStatus(ctx, template)
return ctrl.Result{}, r.updateStatus(ctx, template, "")
}

func (r *TemplateReconciler) parseChartMetadata(template *hmc.Template, chart *chart.Chart) error {
if chart.Metadata == nil {
return fmt.Errorf("chart metadata is empty")
}
templateType := chart.Metadata.Annotations[hmc.ChartAnnotationType]
infraProvider := chart.Metadata.Annotations[hmc.ChartAnnotationInfraProvider]
bootstrapProvider := chart.Metadata.Annotations[hmc.ChartAnnotationBootstrapProvider]

switch hmc.TemplateType(templateType) {
case hmc.TemplateTypeDeployment:
if infraProvider == "" {
return errNoInfraProvider
}
if bootstrapProvider == "" {
return errNoBootstrapProvider
}
case hmc.TemplateTypeInfraProvider:
if infraProvider == "" {
return errNoInfraProvider
}
case hmc.TemplateTypeBootstrapProvider:
if bootstrapProvider == "" {
return errNoBootstrapProvider
}
case hmc.TemplateTypeManagement:
default:
return errNoProviderType
}
template.Status.Type = templateType
template.Status.InfrastructureProvider = infraProvider
template.Status.BootstrapProvider = bootstrapProvider
return nil
}

func (r *TemplateReconciler) updateStatus(ctx context.Context, template *hmc.Template) error {
func (r *TemplateReconciler) updateStatus(ctx context.Context, template *hmc.Template, validationError string) error {
template.Status.ObservedGeneration = template.Generation
template.Status.ValidationError = validationError
template.Status.Valid = validationError == ""
if err := r.Status().Update(ctx, template); err != nil {
return fmt.Errorf("failed to update status for template %s/%s: %w", template.Namespace, template.Name, err)
}
Expand Down
1 change: 0 additions & 1 deletion internal/controller/template_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ var _ = Describe("Template Controller", func() {
Namespace: "default",
},
Spec: hmcmirantiscomv1alpha1.TemplateSpec{
Provider: "aws",
Helm: hmcmirantiscomv1alpha1.HelmSpec{
ChartRef: &v2.CrossNamespaceSourceReference{
Kind: "HelmChart",
Expand Down

0 comments on commit 33555ea

Please sign in to comment.