Skip to content

Commit

Permalink
feat(controller): use CRD status subresource
Browse files Browse the repository at this point in the history
Signed-off-by: Jesse Suen <[email protected]>
  • Loading branch information
jessesuen committed Nov 7, 2020
1 parent ac74a9b commit b5ab88e
Show file tree
Hide file tree
Showing 33 changed files with 275 additions and 280 deletions.
3 changes: 1 addition & 2 deletions manifests/crds/rollout-crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ spec:
labelSelectorPath: .status.selector
specReplicasPath: .spec.replicas
statusReplicasPath: .status.HPAReplicas
status: {}
validation:
openAPIV3Schema:
properties:
Expand Down Expand Up @@ -3059,8 +3060,6 @@ spec:
- name
- status
type: object
stableRS:
type: string
type: object
collisionCount:
format: int32
Expand Down
9 changes: 5 additions & 4 deletions manifests/install.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11057,11 +11057,13 @@ spec:
name: Current
type: integer
- JSONPath: .status.updatedReplicas
description: Total number of non-terminated pods targeted by this rollout that have the desired template spec
description: Total number of non-terminated pods targeted by this rollout that
have the desired template spec
name: Up-to-date
type: integer
- JSONPath: .status.availableReplicas
description: Total number of available pods (ready for at least minReadySeconds) targeted by this rollout
description: Total number of available pods (ready for at least minReadySeconds)
targeted by this rollout
name: Available
type: integer
group: argoproj.io
Expand All @@ -11078,6 +11080,7 @@ spec:
labelSelectorPath: .status.selector
specReplicasPath: .spec.replicas
statusReplicasPath: .status.HPAReplicas
status: {}
validation:
openAPIV3Schema:
properties:
Expand Down Expand Up @@ -14101,8 +14104,6 @@ spec:
- name
- status
type: object
stableRS:
type: string
type: object
collisionCount:
format: int32
Expand Down
9 changes: 5 additions & 4 deletions manifests/namespace-install.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11057,11 +11057,13 @@ spec:
name: Current
type: integer
- JSONPath: .status.updatedReplicas
description: Total number of non-terminated pods targeted by this rollout that have the desired template spec
description: Total number of non-terminated pods targeted by this rollout that
have the desired template spec
name: Up-to-date
type: integer
- JSONPath: .status.availableReplicas
description: Total number of available pods (ready for at least minReadySeconds) targeted by this rollout
description: Total number of available pods (ready for at least minReadySeconds)
targeted by this rollout
name: Available
type: integer
group: argoproj.io
Expand All @@ -11078,6 +11080,7 @@ spec:
labelSelectorPath: .status.selector
specReplicasPath: .spec.replicas
statusReplicasPath: .status.HPAReplicas
status: {}
validation:
openAPIV3Schema:
properties:
Expand Down Expand Up @@ -14101,8 +14104,6 @@ spec:
- name
- status
type: object
stableRS:
type: string
type: object
collisionCount:
format: int32
Expand Down
7 changes: 0 additions & 7 deletions pkg/apis/rollouts/v1alpha1/openapi_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 1 addition & 4 deletions pkg/apis/rollouts/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ import (
)

// +genclient
// +genclient:noStatus
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +kubebuilder:resource:path=rollouts,shortName=ro
// +kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.HPAReplicas,selectorpath=.status.selector
// +kubebuilder:printcolumn:name="Desired",type="integer",JSONPath=".spec.replicas",description="Number of desired pods"
// +kubebuilder:printcolumn:name="Current",type="integer",JSONPath=".status.replicas",description="Total number of non-terminated pods targeted by this rollout"
// +kubebuilder:printcolumn:name="Up-to-date",type="integer",JSONPath=".status.updatedReplicas",description="Total number of non-terminated pods targeted by this rollout that have the desired template spec"
// +kubebuilder:printcolumn:name="Available",type="integer",JSONPath=".status.availableReplicas",description="Total number of available pods (ready for at least minReadySeconds) targeted by this rollout"
// +kubebuilder:subresource:status

// Rollout is a specification for a Rollout resource
type Rollout struct {
Expand Down Expand Up @@ -599,9 +599,6 @@ type BlueGreenStatus struct {

// CanaryStatus status fields that only pertain to the canary rollout
type CanaryStatus struct {
// StableRS indicates the last replicaset that walked through all the canary steps or was the only replicaset
// +optional
StableRS string `json:"stableRS,omitempty"`
// CurrentStepAnalysisRun indicates the analysisRun for the current step index
// TODO(Deprecated): Remove in v0.10
CurrentStepAnalysisRun string `json:"currentStepAnalysisRun,omitempty"`
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions pkg/client/clientset/versioned/typed/rollouts/v1alpha1/rollout.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion pkg/kubectl-argo-rollouts/cmd/abort/abort.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"

"github.com/spf13/cobra"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"

Expand Down Expand Up @@ -58,5 +59,10 @@ func NewCmdAbort(o *options.ArgoRolloutsOptions) *cobra.Command {
// AbortRollout aborts a rollout
func AbortRollout(rolloutIf clientset.RolloutInterface, name string) (*v1alpha1.Rollout, error) {
ctx := context.TODO()
return rolloutIf.Patch(ctx, name, types.MergePatchType, []byte(abortPatch), metav1.PatchOptions{})
// attempt using status subresource, first
ro, err := rolloutIf.Patch(ctx, name, types.MergePatchType, []byte(abortPatch), metav1.PatchOptions{}, "status")
if err != nil && k8serrors.IsNotFound(err) {
ro, err = rolloutIf.Patch(ctx, name, types.MergePatchType, []byte(abortPatch), metav1.PatchOptions{})
}
return ro, err
}
3 changes: 3 additions & 0 deletions pkg/kubectl-argo-rollouts/cmd/get/get_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ func TestGetBlueGreenRollout(t *testing.T) {
Name: bluegreen-demo
Namespace: jesse-test
Status: ॥ Paused
Message: BlueGreenPause
Strategy: BlueGreen
Images: argoproj/rollouts-demo:blue (stable, active)
argoproj/rollouts-demo:green (preview)
Expand Down Expand Up @@ -165,6 +166,7 @@ func TestGetBlueGreenRolloutScaleDownDelay(t *testing.T) {
Name: bluegreen-demo
Namespace: jesse-test
Status: ॥ Paused
Message: BlueGreenPause
Strategy: BlueGreen
Images: argoproj/rollouts-demo:blue (stable, active)
argoproj/rollouts-demo:green
Expand Down Expand Up @@ -212,6 +214,7 @@ func TestGetBlueGreenRolloutScaleDownDelayPassed(t *testing.T) {
Name: bluegreen-demo
Namespace: jesse-test
Status: ॥ Paused
Message: BlueGreenPause
Strategy: BlueGreen
Images: argoproj/rollouts-demo:blue (stable, active)
argoproj/rollouts-demo:green
Expand Down
75 changes: 52 additions & 23 deletions pkg/kubectl-argo-rollouts/cmd/promote/promote.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"

"github.com/spf13/cobra"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"

Expand All @@ -29,20 +30,12 @@ If not on a pause step use '--skip-current-step' to progress to the next step in
)

const (
setCurrentStepIndex = `{
"status": {
"currentStepIndex": %d
}
}`
setCurrentStepIndex = `{"status":{"currentStepIndex":%d}}`
unpausePatch = `{"spec":{"paused":false}}`
clearPauseConditionsPatch = `{"status":{"pauseConditions":null}}`
unpauseAndClearPauseConditionsPatch = `{"spec":{"paused":false},"status":{"pauseConditions":null}}`
fullPromotionPatch = `{"status":{"stableRS":"%s"}}`

unpausePatch = `{
"spec": {
"paused": false
},
"status": {
"pauseConditions": null
}
}`
useBothSkipFlagsError = "Cannot use skip-current-step and skip-all-steps flags at the same time"
skipFlagsWithBlueGreenError = "Cannot skip steps of a bluegreen rollout. Run without a flags"
skipFlagWithNoStepCanaryError = "Cannot skip steps of a rollout without steps"
Expand All @@ -53,6 +46,7 @@ func NewCmdPromote(o *options.ArgoRolloutsOptions) *cobra.Command {
var (
skipCurrentStep = false
skipAllSteps = false
full = false
)
var cmd = &cobra.Command{
Use: "promote ROLLOUT_NAME",
Expand All @@ -69,7 +63,7 @@ func NewCmdPromote(o *options.ArgoRolloutsOptions) *cobra.Command {
}
name := args[0]
rolloutIf := o.RolloutsClientset().ArgoprojV1alpha1().Rollouts(o.Namespace())
ro, err := PromoteRollout(rolloutIf, name, skipCurrentStep, skipAllSteps)
ro, err := PromoteRollout(rolloutIf, name, skipCurrentStep, skipAllSteps, full)
if err != nil {
return err
}
Expand All @@ -79,11 +73,12 @@ func NewCmdPromote(o *options.ArgoRolloutsOptions) *cobra.Command {
}
cmd.Flags().BoolVarP(&skipCurrentStep, "skip-current-step", "c", false, "Skip current step")
cmd.Flags().BoolVarP(&skipAllSteps, "skip-all-steps", "a", false, "Skip remaining steps")
cmd.Flags().BoolVar(&full, "full", false, "Perform a full promotion (skip analysis, pausing)")
return cmd
}

// PromoteRollout promotes a rollout to the next step, or to end of all steps
func PromoteRollout(rolloutIf clientset.RolloutInterface, name string, skipCurrentStep, skipAllSteps bool) (*v1alpha1.Rollout, error) {
func PromoteRollout(rolloutIf clientset.RolloutInterface, name string, skipCurrentStep, skipAllSteps, full bool) (*v1alpha1.Rollout, error) {
ctx := context.TODO()
ro, err := rolloutIf.Get(ctx, name, metav1.GetOptions{})
if err != nil {
Expand All @@ -97,15 +92,37 @@ func PromoteRollout(rolloutIf clientset.RolloutInterface, name string, skipCurre
return nil, fmt.Errorf(skipFlagWithNoStepCanaryError)
}
}
patch := getPatch(ro, skipCurrentStep, skipAllSteps)
ro, err = rolloutIf.Patch(ctx, name, types.MergePatchType, patch, metav1.PatchOptions{})
if err != nil {
return nil, err

// This function is intended to be compatible with Rollouts v0.9 and Rollouts v0.10+, the latter
// of which uses CRD status subresources. When using status subresource, status must be updated
// separately from spec. Since we don't know which version is installed in the cluster, we
// attempt status patching first. If it errors with NotFound, it indicates that status
// subresource is not used (v0.9), at which point we need to use the unified patch that updates
// both spec and status. Otherwise, we proceed with a spec only patch.
// NOTE: this logic can be simplified in the future once we can safely assume users are using
// v0.10+, and wish to drop support for v0.9 and below
specPatch, statusPatch, unifiedPatch := getPatches(ro, skipCurrentStep, skipAllSteps, full)
if statusPatch != nil {
ro, err = rolloutIf.Patch(ctx, name, types.MergePatchType, statusPatch, metav1.PatchOptions{}, "status")
if err != nil {
if !k8serrors.IsNotFound(err) {
return nil, err
}
// we got a NotFound error. status subresource is not being used, so perform unifiedPatch
specPatch = unifiedPatch
}
}
if specPatch != nil {
ro, err = rolloutIf.Patch(ctx, name, types.MergePatchType, specPatch, metav1.PatchOptions{})
if err != nil {
return nil, err
}
}
return ro, nil
}

func getPatch(rollout *v1alpha1.Rollout, skipCurrentStep, skipAllStep bool) []byte {
func getPatches(rollout *v1alpha1.Rollout, skipCurrentStep, skipAllStep, full bool) ([]byte, []byte, []byte) {
var specPatch, statusPatch, unifiedPatch []byte
switch {
case skipCurrentStep:
_, index := replicasetutil.GetCurrentCanaryStep(rollout)
Expand All @@ -114,10 +131,22 @@ func getPatch(rollout *v1alpha1.Rollout, skipCurrentStep, skipAllStep bool) []by
if *index < int32(len(rollout.Spec.Strategy.Canary.Steps)) {
*index++
}
return []byte(fmt.Sprintf(setCurrentStepIndex, *index))
statusPatch = []byte(fmt.Sprintf(setCurrentStepIndex, *index))
unifiedPatch = statusPatch
case skipAllStep:
return []byte(fmt.Sprintf(setCurrentStepIndex, len(rollout.Spec.Strategy.Canary.Steps)))
statusPatch = []byte(fmt.Sprintf(setCurrentStepIndex, len(rollout.Spec.Strategy.Canary.Steps)))
unifiedPatch = statusPatch
case full:
statusPatch = []byte(fmt.Sprintf(fullPromotionPatch, rollout.Status.CurrentPodHash))
unifiedPatch = statusPatch
default:
return []byte(unpausePatch)
if rollout.Spec.Paused {
specPatch = []byte(unpausePatch)
}
if len(rollout.Status.PauseConditions) > 0 {
statusPatch = []byte(clearPauseConditionsPatch)
}
unifiedPatch = []byte(unpauseAndClearPauseConditionsPatch)
}
return specPatch, statusPatch, unifiedPatch
}
8 changes: 7 additions & 1 deletion pkg/kubectl-argo-rollouts/cmd/retry/retry.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"

"github.com/spf13/cobra"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"

Expand Down Expand Up @@ -82,7 +83,12 @@ func NewCmdRetryRollout(o *options.ArgoRolloutsOptions) *cobra.Command {
// RetryRollout retries a rollout after it's been aborted
func RetryRollout(rolloutIf clientset.RolloutInterface, name string) (*v1alpha1.Rollout, error) {
ctx := context.TODO()
return rolloutIf.Patch(ctx, name, types.MergePatchType, []byte(retryRolloutPatch), metav1.PatchOptions{})
// attempt using status subresource, first
ro, err := rolloutIf.Patch(ctx, name, types.MergePatchType, []byte(retryRolloutPatch), metav1.PatchOptions{}, "status")
if err != nil && k8serrors.IsNotFound(err) {
ro, err = rolloutIf.Patch(ctx, name, types.MergePatchType, []byte(retryRolloutPatch), metav1.PatchOptions{})
}
return ro, err
}

// NewCmdRetryExperiment returns a new instance of an `argo rollouts retry experiment` command
Expand Down
Loading

0 comments on commit b5ab88e

Please sign in to comment.