Add changes to Armada Charts CRD
Allow tracking of helm status, resource wait and tests. Change-Id: I9e4de81272c7471f326679d5c4b4427cbf836797 Signed-off-by: Ruslan Aliev <raliev@mirantis.com>
This commit is contained in:
parent
d557f99c8f
commit
0f3ef2a6c9
@ -172,10 +172,19 @@ type ArmadaChartStatus struct {
|
|||||||
// +optional
|
// +optional
|
||||||
UpgradeFailures int64 `json:"upgradeFailures,omitempty"`
|
UpgradeFailures int64 `json:"upgradeFailures,omitempty"`
|
||||||
|
|
||||||
|
// HelmStatus describes the status of helm release
|
||||||
|
// +optional
|
||||||
|
HelmStatus string `json:"helmStatus,omitempty"`
|
||||||
|
|
||||||
// Tested is the bool value whether the Helm Release was successfully
|
// Tested is the bool value whether the Helm Release was successfully
|
||||||
// tested or not.
|
// tested or not.
|
||||||
// +optional
|
// +optional
|
||||||
Tested bool `json:"tested,omitempty"`
|
Tested bool `json:"tested,omitempty"`
|
||||||
|
|
||||||
|
// WaitCompleted is the bool value whether the Helm Release resources were
|
||||||
|
// waited for or not.
|
||||||
|
// +optional
|
||||||
|
WaitCompleted bool `json:"waitCompleted,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ArmadaChartProgressing resets any failures and registers progress toward
|
// ArmadaChartProgressing resets any failures and registers progress toward
|
||||||
@ -191,7 +200,9 @@ func ArmadaChartProgressing(ac ArmadaChart) ArmadaChart {
|
|||||||
}
|
}
|
||||||
apimeta.SetStatusCondition(ac.GetStatusConditions(), newCondition)
|
apimeta.SetStatusCondition(ac.GetStatusConditions(), newCondition)
|
||||||
resetFailureCounts(&ac)
|
resetFailureCounts(&ac)
|
||||||
|
resetWaitCompleted(&ac)
|
||||||
resetTested(&ac)
|
resetTested(&ac)
|
||||||
|
ac.Status.HelmStatus = "Unknown"
|
||||||
return ac
|
return ac
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,6 +249,14 @@ func setTested(hr *ArmadaChart) {
|
|||||||
hr.Status.Tested = true
|
hr.Status.Tested = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resetWaitCompleted(hr *ArmadaChart) {
|
||||||
|
hr.Status.WaitCompleted = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func setWaitCompleted(hr *ArmadaChart) {
|
||||||
|
hr.Status.WaitCompleted = true
|
||||||
|
}
|
||||||
|
|
||||||
func NewForConfigOrDie(c *rest.Config) *rest.RESTClient {
|
func NewForConfigOrDie(c *rest.Config) *rest.RESTClient {
|
||||||
cs, err := NewForConfig(c)
|
cs, err := NewForConfig(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -280,6 +299,13 @@ func setConfigDefaults(config *rest.Config) error {
|
|||||||
|
|
||||||
//+kubebuilder:object:root=true
|
//+kubebuilder:object:root=true
|
||||||
//+kubebuilder:subresource:status
|
//+kubebuilder:subresource:status
|
||||||
|
// +kubebuilder:printcolumn:name="Namespace",type=string,JSONPath=`.metadata.namespace`
|
||||||
|
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
|
||||||
|
// +kubebuilder:printcolumn:name="Ready",type=boolean,JSONPath=`.status.conditions[?(@.type=="Ready")].status`
|
||||||
|
// +kubebuilder:printcolumn:name="Message",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].message`,priority=10
|
||||||
|
// +kubebuilder:printcolumn:name="Helm Status",type=string,JSONPath=`.status.helmStatus`
|
||||||
|
// +kubebuilder:printcolumn:name="Wait Completed",type=boolean,JSONPath=`.status.waitCompleted`
|
||||||
|
// +kubebuilder:printcolumn:name="Tested",type=boolean,JSONPath=`.status.tested`
|
||||||
|
|
||||||
// ArmadaChart is the Schema for the armadacharts API
|
// ArmadaChart is the Schema for the armadacharts API
|
||||||
type ArmadaChart struct {
|
type ArmadaChart struct {
|
||||||
|
@ -14,7 +14,30 @@ spec:
|
|||||||
singular: armadachart
|
singular: armadachart
|
||||||
scope: Namespaced
|
scope: Namespaced
|
||||||
versions:
|
versions:
|
||||||
- name: v1
|
- additionalPrinterColumns:
|
||||||
|
- jsonPath: .metadata.namespace
|
||||||
|
name: Namespace
|
||||||
|
type: string
|
||||||
|
- jsonPath: .metadata.creationTimestamp
|
||||||
|
name: Age
|
||||||
|
type: date
|
||||||
|
- jsonPath: .status.conditions[?(@.type=="Ready")].status
|
||||||
|
name: Ready
|
||||||
|
type: boolean
|
||||||
|
- jsonPath: .status.conditions[?(@.type=="Ready")].message
|
||||||
|
name: Message
|
||||||
|
priority: 10
|
||||||
|
type: string
|
||||||
|
- jsonPath: .status.helmStatus
|
||||||
|
name: Helm Status
|
||||||
|
type: string
|
||||||
|
- jsonPath: .status.waitCompleted
|
||||||
|
name: Wait Completed
|
||||||
|
type: boolean
|
||||||
|
- jsonPath: .status.tested
|
||||||
|
name: Tested
|
||||||
|
type: boolean
|
||||||
|
name: v1
|
||||||
schema:
|
schema:
|
||||||
openAPIV3Schema:
|
openAPIV3Schema:
|
||||||
description: ArmadaChart is the Schema for the armadacharts API
|
description: ArmadaChart is the Schema for the armadacharts API
|
||||||
@ -200,6 +223,9 @@ spec:
|
|||||||
description: HelmChart is the namespaced name of the HelmChart resource
|
description: HelmChart is the namespaced name of the HelmChart resource
|
||||||
created by the controller for the ArmadaChart.
|
created by the controller for the ArmadaChart.
|
||||||
type: string
|
type: string
|
||||||
|
helmStatus:
|
||||||
|
description: HelmStatus describes the status of helm release
|
||||||
|
type: string
|
||||||
installFailures:
|
installFailures:
|
||||||
description: InstallFailures is the install failure count against
|
description: InstallFailures is the install failure count against
|
||||||
the latest desired state. It is reset after a successful reconciliation.
|
the latest desired state. It is reset after a successful reconciliation.
|
||||||
@ -234,6 +260,10 @@ spec:
|
|||||||
the latest desired state. It is reset after a successful reconciliation.
|
the latest desired state. It is reset after a successful reconciliation.
|
||||||
format: int64
|
format: int64
|
||||||
type: integer
|
type: integer
|
||||||
|
waitCompleted:
|
||||||
|
description: WaitCompleted is the bool value whether the Helm Release
|
||||||
|
resources were waited for or not.
|
||||||
|
type: boolean
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
served: true
|
served: true
|
||||||
|
@ -129,10 +129,10 @@ func (r *ArmadaChartReconciler) reconcile(ctx context.Context, ac armadav1.Armad
|
|||||||
// Prepare values
|
// Prepare values
|
||||||
var vals map[string]interface{}
|
var vals map[string]interface{}
|
||||||
if ac.Spec.Values != nil {
|
if ac.Spec.Values != nil {
|
||||||
var vals_err error
|
var valsErr error
|
||||||
vals, vals_err = chartutil.ReadValues(ac.Spec.Values.Raw)
|
vals, valsErr = chartutil.ReadValues(ac.Spec.Values.Raw)
|
||||||
if vals_err != nil {
|
if valsErr != nil {
|
||||||
return armadav1.ArmadaChartNotReady(ac, "InitFailed", vals_err.Error()), ctrl.Result{}, vals_err
|
return armadav1.ArmadaChartNotReady(ac, "InitFailed", valsErr.Error()), ctrl.Result{}, valsErr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Load chart from artifact
|
// Load chart from artifact
|
||||||
@ -154,6 +154,10 @@ func (r *ArmadaChartReconciler) reconcileChart(ctx context.Context,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return armadav1.ArmadaChartNotReady(ac, "InitFailed", err.Error()), err
|
return armadav1.ArmadaChartNotReady(ac, "InitFailed", err.Error()), err
|
||||||
}
|
}
|
||||||
|
restCfg, err := gettr.ToRESTConfig()
|
||||||
|
if err != nil {
|
||||||
|
return armadav1.ArmadaChartNotReady(ac, "InitFailed", err.Error()), err
|
||||||
|
}
|
||||||
|
|
||||||
run, err := runner.NewRunner(gettr, ac.Namespace, log)
|
run, err := runner.NewRunner(gettr, ac.Namespace, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -167,24 +171,19 @@ func (r *ArmadaChartReconciler) reconcileChart(ctx context.Context,
|
|||||||
return armadav1.ArmadaChartNotReady(ac, "GetLastReleaseFailed", "failed to get last release revision"), err
|
return armadav1.ArmadaChartNotReady(ac, "GetLastReleaseFailed", "failed to get last release revision"), err
|
||||||
}
|
}
|
||||||
|
|
||||||
testRel := func() (armadav1.ArmadaChart, error) {
|
|
||||||
if ac.Spec.Test.Enabled && !ac.Status.Tested {
|
|
||||||
log.Info("performing tests")
|
|
||||||
rel, err = run.Test(ac)
|
|
||||||
if err != nil {
|
|
||||||
return armadav1.ArmadaChartNotReady(ac, "TestFailed", err.Error()), err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return armadav1.ArmadaChartReady(ac), err
|
|
||||||
}
|
|
||||||
|
|
||||||
if rel == nil {
|
if rel == nil {
|
||||||
log.Info("helm install has started")
|
log.Info("helm install has started")
|
||||||
rel, err = run.Install(ctx, ac, chrt, vals)
|
rel, err = run.Install(ctx, ac, chrt, vals)
|
||||||
} else {
|
} else {
|
||||||
|
ac.Status.HelmStatus = string(rel.Info.Status)
|
||||||
|
if updateStatusErr := r.patchStatus(ctx, &ac); updateStatusErr != nil {
|
||||||
|
log.Error(updateStatusErr, "unable to update status after helm status update")
|
||||||
|
return armadav1.ArmadaChartNotReady(ac, "UpdateStatusFailed", updateStatusErr.Error()), updateStatusErr
|
||||||
|
}
|
||||||
|
|
||||||
if rel.Info.Status == release.StatusDeployed && !isUpdateRequired(ctx, rel, chrt, vals) {
|
if rel.Info.Status == release.StatusDeployed && !isUpdateRequired(ctx, rel, chrt, vals) {
|
||||||
log.Info("no updates found, skipping upgrade")
|
log.Info("no updates found, skipping upgrade")
|
||||||
return testRel()
|
return r.finalizeRelease(ctx, run, restCfg, ac)
|
||||||
}
|
}
|
||||||
|
|
||||||
if rel.Info.Status.IsPending() {
|
if rel.Info.Status.IsPending() {
|
||||||
@ -221,25 +220,36 @@ func (r *ArmadaChartReconciler) reconcileChart(ctx context.Context,
|
|||||||
err = fmt.Errorf("failed to install/upgrade helm release: %s", err.Error())
|
err = fmt.Errorf("failed to install/upgrade helm release: %s", err.Error())
|
||||||
return armadav1.ArmadaChartNotReady(ac, "InstallUpgradeFailed", err.Error()), err
|
return armadav1.ArmadaChartNotReady(ac, "InstallUpgradeFailed", err.Error()), err
|
||||||
}
|
}
|
||||||
|
ac.Status.HelmStatus = string(rel.Info.Status)
|
||||||
if ac.Spec.Wait.Timeout > 0 && len(ac.Spec.Wait.Labels) > 0 {
|
if err := r.patchStatus(ctx, &ac); err != nil {
|
||||||
log.Info("preparing to wait resources")
|
log.Error(err, "unable to update armadachart status")
|
||||||
resCfg, err := gettr.ToRESTConfig()
|
|
||||||
if err != nil {
|
|
||||||
return armadav1.ArmadaChartNotReady(ac, "WaitFailed", err.Error()), err
|
|
||||||
}
|
|
||||||
err = r.waitRelease(ctx, resCfg, ac)
|
|
||||||
if err != nil {
|
|
||||||
return armadav1.ArmadaChartNotReady(ac, "WaitFailed", err.Error()), err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return testRel()
|
return r.finalizeRelease(ctx, run, restCfg, ac)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ArmadaChartReconciler) waitRelease(ctx context.Context, restCfg *rest.Config, hr armadav1.ArmadaChart) error {
|
func (r *ArmadaChartReconciler) finalizeRelease(ctx context.Context, run *runner.Runner, restCfg *rest.Config, hr armadav1.ArmadaChart) (armadav1.ArmadaChart, error) {
|
||||||
|
hr, err := r.waitRelease(ctx, restCfg, hr)
|
||||||
|
if err != nil {
|
||||||
|
return hr, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.testRelease(ctx, run, hr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ArmadaChartReconciler) waitRelease(ctx context.Context, restCfg *rest.Config, hr armadav1.ArmadaChart) (armadav1.ArmadaChart, error) {
|
||||||
log := ctrl.LoggerFrom(ctx)
|
log := ctrl.LoggerFrom(ctx)
|
||||||
|
|
||||||
|
if hr.Status.WaitCompleted {
|
||||||
|
log.Info("wait has been already completed")
|
||||||
|
return hr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if hr.Spec.Wait.Timeout == 0 {
|
||||||
|
log.Info("No Chart timeout specified, using default 900s")
|
||||||
|
hr.Spec.Wait.Timeout = 900
|
||||||
|
}
|
||||||
|
|
||||||
if hr.Spec.Wait.ArmadaChartWaitResources == nil {
|
if hr.Spec.Wait.ArmadaChartWaitResources == nil {
|
||||||
log.Info(fmt.Sprintf("there are no explicitly defined resources to wait: %s, using default ones", hr.Name))
|
log.Info(fmt.Sprintf("there are no explicitly defined resources to wait: %s, using default ones", hr.Name))
|
||||||
hr.Spec.Wait.ArmadaChartWaitResources = []armadav1.ArmadaChartWaitResource{{Type: "job"}, {Type: "pod"}}
|
hr.Spec.Wait.ArmadaChartWaitResources = []armadav1.ArmadaChartWaitResource{{Type: "job"}, {Type: "pod"}}
|
||||||
@ -288,12 +298,28 @@ func (r *ArmadaChartReconciler) waitRelease(ctx context.Context, restCfg *rest.C
|
|||||||
}
|
}
|
||||||
err := opts.Wait(ctx)
|
err := opts.Wait(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return hr, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("all resources are ready")
|
log.Info("all resources are ready")
|
||||||
return nil
|
hr.Status.WaitCompleted = true
|
||||||
|
if err := r.patchStatus(ctx, &hr); err != nil {
|
||||||
|
return hr, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return hr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ArmadaChartReconciler) testRelease(ctx context.Context, run *runner.Runner, ac armadav1.ArmadaChart) (armadav1.ArmadaChart, error) {
|
||||||
|
log := ctrl.LoggerFrom(ctx)
|
||||||
|
if ac.Spec.Test.Enabled && !ac.Status.Tested {
|
||||||
|
log.Info("performing tests")
|
||||||
|
if _, err := run.Test(ac); err != nil {
|
||||||
|
return armadav1.ArmadaChartNotReady(ac, "TestFailed", err.Error()), err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return armadav1.ArmadaChartReady(ac), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadHelmChart attempts to download the artifact from the provided source,
|
// loadHelmChart attempts to download the artifact from the provided source,
|
||||||
@ -372,6 +398,7 @@ func (r *ArmadaChartReconciler) reconcileDelete(ctx context.Context, ac *armadav
|
|||||||
|
|
||||||
// Remove our finalizer from the list and update it.
|
// Remove our finalizer from the list and update it.
|
||||||
controllerutil.RemoveFinalizer(ac, armadav1.ArmadaChartFinalizer)
|
controllerutil.RemoveFinalizer(ac, armadav1.ArmadaChartFinalizer)
|
||||||
|
ac.Status.HelmStatus = string(release.StatusUninstalled)
|
||||||
if err := r.Update(ctx, ac); err != nil {
|
if err := r.Update(ctx, ac); err != nil {
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user