mirror of
https://github.com/kubevela/kubevela.git
synced 2026-02-14 18:10:21 +00:00
rename applicationDeployment to appRollout (#1146)
* rename applicationDeployment to appRollout * Update test/e2e-test/rollout_plan_test.go Co-authored-by: Jianbo Sun <wonderflow.sun@gmail.com> Co-authored-by: Jianbo Sun <wonderflow.sun@gmail.com>
This commit is contained in:
@@ -22,11 +22,11 @@ import (
|
||||
"github.com/oam-dev/kubevela/apis/standard.oam.dev/v1alpha1"
|
||||
)
|
||||
|
||||
// ApplicationDeploymentSpec defines how to describe an upgrade between different application
|
||||
type ApplicationDeploymentSpec struct {
|
||||
// TargetApplicationName contains the name of the applicationConfiguration that we need to upgrade to.
|
||||
// AppRolloutSpec defines how to describe an upgrade between different apps
|
||||
type AppRolloutSpec struct {
|
||||
// TargetAppRevisionName contains the name of the applicationConfiguration that we need to upgrade to.
|
||||
// Here we use an applicationConfiguration as a revision of an application, thus the name alone is suffice
|
||||
TargetApplicationName string `json:"targetApplicationName"`
|
||||
TargetAppRevisionName string `json:"targetApplicationName"`
|
||||
|
||||
// SourceApplicationName contains the name of the applicationConfiguration that we need to upgrade from.
|
||||
// it can be empty only when it's the first time to deploy the application
|
||||
@@ -42,40 +42,40 @@ type ApplicationDeploymentSpec struct {
|
||||
RolloutPlan v1alpha1.RolloutPlan `json:"rolloutPlan"`
|
||||
|
||||
// RevertOnDelete revert the rollout when the rollout CR is deleted
|
||||
// It will remove the target application from the kubernetes if it's set to true
|
||||
// It will remove the target app from the kubernetes if it's set to true
|
||||
// +optional
|
||||
RevertOnDelete *bool `json:"revertOnDelete,omitempty"`
|
||||
}
|
||||
|
||||
// ApplicationDeploymentStatus defines the observed state of ApplicationDeployment
|
||||
type ApplicationDeploymentStatus struct {
|
||||
// AppRolloutStatus defines the observed state of AppRollout
|
||||
type AppRolloutStatus struct {
|
||||
v1alpha1.RolloutStatus `json:",inline"`
|
||||
|
||||
// LastTargetApplicationName contains the name of the application that we upgraded to
|
||||
// LastTargetAppName contains the name of the app that we upgraded to
|
||||
// We will restart the rollout if this is not the same as the spec
|
||||
LastTargetApplicationName string `json:"lastTargetApplicationName"`
|
||||
LastTargetAppName string `json:"lastTargetAppName"`
|
||||
|
||||
// LastSourceApplicationName contains the name of the application that we need to upgrade from.
|
||||
// LastSourceAppName contains the name of the app that we need to upgrade from.
|
||||
// We will restart the rollout if this is not the same as the spec
|
||||
LastSourceApplicationName string `json:"lastSourceApplicationName,omitempty"`
|
||||
LastSourceAppName string `json:"LastSourceAppName,omitempty"`
|
||||
}
|
||||
|
||||
// ApplicationDeployment is the Schema for the ApplicationDeployment API
|
||||
// AppRollout is the Schema for the AppRollout API
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:resource:categories={oam}
|
||||
// +kubebuilder:subresource:status
|
||||
type ApplicationDeployment struct {
|
||||
type AppRollout struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec ApplicationDeploymentSpec `json:"spec,omitempty"`
|
||||
Status ApplicationDeploymentStatus `json:"status,omitempty"`
|
||||
Spec AppRolloutSpec `json:"spec,omitempty"`
|
||||
Status AppRolloutStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// ApplicationDeploymentList contains a list of ApplicationDeployment
|
||||
// AppRolloutList contains a list of AppRollout
|
||||
// +kubebuilder:object:root=true
|
||||
type ApplicationDeploymentList struct {
|
||||
type AppRolloutList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []ApplicationDeployment `json:"items"`
|
||||
Items []AppRollout `json:"items"`
|
||||
}
|
||||
|
||||
@@ -111,10 +111,10 @@ var (
|
||||
|
||||
// Application type metadata.
|
||||
var (
|
||||
ApplicationDeploymentKind = reflect.TypeOf(ApplicationDeployment{}).Name()
|
||||
ApplicationDeploymentGroupKind = schema.GroupKind{Group: Group, Kind: ApplicationDeploymentKind}.String()
|
||||
ApplicationDeploymentKindAPIVersion = ApplicationKind + "." + SchemeGroupVersion.String()
|
||||
ApplicationDeploymentKindVersionKind = SchemeGroupVersion.WithKind(ApplicationDeploymentKind)
|
||||
AppRolloutKind = reflect.TypeOf(AppRollout{}).Name()
|
||||
AppRolloutGroupKind = schema.GroupKind{Group: Group, Kind: AppRolloutKind}.String()
|
||||
AppRolloutKindAPIVersion = ApplicationKind + "." + SchemeGroupVersion.String()
|
||||
AppRolloutKindVersionKind = SchemeGroupVersion.WithKind(AppRolloutKind)
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -127,5 +127,5 @@ func init() {
|
||||
SchemeBuilder.Register(&ManualScalerTrait{}, &ManualScalerTraitList{})
|
||||
SchemeBuilder.Register(&HealthScope{}, &HealthScopeList{})
|
||||
SchemeBuilder.Register(&Application{}, &ApplicationList{})
|
||||
SchemeBuilder.Register(&ApplicationDeployment{}, &ApplicationDeploymentList{})
|
||||
SchemeBuilder.Register(&AppRollout{}, &AppRolloutList{})
|
||||
}
|
||||
|
||||
@@ -26,6 +26,107 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AppRollout) DeepCopyInto(out *AppRollout) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AppRollout.
|
||||
func (in *AppRollout) DeepCopy() *AppRollout {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AppRollout)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *AppRollout) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AppRolloutList) DeepCopyInto(out *AppRolloutList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]AppRollout, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AppRolloutList.
|
||||
func (in *AppRolloutList) DeepCopy() *AppRolloutList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AppRolloutList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *AppRolloutList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AppRolloutSpec) DeepCopyInto(out *AppRolloutSpec) {
|
||||
*out = *in
|
||||
if in.ComponentList != nil {
|
||||
in, out := &in.ComponentList, &out.ComponentList
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
in.RolloutPlan.DeepCopyInto(&out.RolloutPlan)
|
||||
if in.RevertOnDelete != nil {
|
||||
in, out := &in.RevertOnDelete, &out.RevertOnDelete
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AppRolloutSpec.
|
||||
func (in *AppRolloutSpec) DeepCopy() *AppRolloutSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AppRolloutSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AppRolloutStatus) DeepCopyInto(out *AppRolloutStatus) {
|
||||
*out = *in
|
||||
in.RolloutStatus.DeepCopyInto(&out.RolloutStatus)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AppRolloutStatus.
|
||||
func (in *AppRolloutStatus) DeepCopy() *AppRolloutStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AppRolloutStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AppStatus) DeepCopyInto(out *AppStatus) {
|
||||
*out = *in
|
||||
@@ -292,107 +393,6 @@ func (in *ApplicationConfigurationStatus) DeepCopy() *ApplicationConfigurationSt
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ApplicationDeployment) DeepCopyInto(out *ApplicationDeployment) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDeployment.
|
||||
func (in *ApplicationDeployment) DeepCopy() *ApplicationDeployment {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ApplicationDeployment)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ApplicationDeployment) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ApplicationDeploymentList) DeepCopyInto(out *ApplicationDeploymentList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]ApplicationDeployment, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDeploymentList.
|
||||
func (in *ApplicationDeploymentList) DeepCopy() *ApplicationDeploymentList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ApplicationDeploymentList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ApplicationDeploymentList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ApplicationDeploymentSpec) DeepCopyInto(out *ApplicationDeploymentSpec) {
|
||||
*out = *in
|
||||
if in.ComponentList != nil {
|
||||
in, out := &in.ComponentList, &out.ComponentList
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
in.RolloutPlan.DeepCopyInto(&out.RolloutPlan)
|
||||
if in.RevertOnDelete != nil {
|
||||
in, out := &in.RevertOnDelete, &out.RevertOnDelete
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDeploymentSpec.
|
||||
func (in *ApplicationDeploymentSpec) DeepCopy() *ApplicationDeploymentSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ApplicationDeploymentSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ApplicationDeploymentStatus) DeepCopyInto(out *ApplicationDeploymentStatus) {
|
||||
*out = *in
|
||||
in.RolloutStatus.DeepCopyInto(&out.RolloutStatus)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDeploymentStatus.
|
||||
func (in *ApplicationDeploymentStatus) DeepCopy() *ApplicationDeploymentStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ApplicationDeploymentStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ApplicationList) DeepCopyInto(out *ApplicationList) {
|
||||
*out = *in
|
||||
|
||||
351
charts/vela-core/crds/core.oam.dev_approllouts.yaml
Normal file
351
charts/vela-core/crds/core.oam.dev_approllouts.yaml
Normal file
@@ -0,0 +1,351 @@
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.2.4
|
||||
creationTimestamp: null
|
||||
name: approllouts.core.oam.dev
|
||||
spec:
|
||||
group: core.oam.dev
|
||||
names:
|
||||
categories:
|
||||
- oam
|
||||
kind: AppRollout
|
||||
listKind: AppRolloutList
|
||||
plural: approllouts
|
||||
singular: approllout
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- name: v1alpha2
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: AppRollout is the Schema for the AppRollout API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: AppRolloutSpec defines how to describe an upgrade between different apps
|
||||
properties:
|
||||
componentList:
|
||||
description: 'The list of component to upgrade in the application. We only support single component application so far TODO: (RZ) Support multiple components in an application'
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
revertOnDelete:
|
||||
description: RevertOnDelete revert the rollout when the rollout CR is deleted It will remove the target app from the kubernetes if it's set to true
|
||||
type: boolean
|
||||
rolloutPlan:
|
||||
description: RolloutPlan is the details on how to rollout the resources
|
||||
properties:
|
||||
batchPartition:
|
||||
description: All pods in the batches up to the batchPartition (included) will have the target resource specification while the rest still have the source resource This is designed for the operators to manually rollout Default is the the number of batches which will rollout all the batches
|
||||
format: int32
|
||||
type: integer
|
||||
canaryMetric:
|
||||
description: CanaryMetric provides a way for the rollout process to automatically check certain metrics before complete the process
|
||||
items:
|
||||
description: CanaryMetric holds the reference to metrics used for canary analysis
|
||||
properties:
|
||||
interval:
|
||||
description: Interval represents the windows size
|
||||
type: string
|
||||
metricsRange:
|
||||
description: Range value accepted for this metric
|
||||
properties:
|
||||
max:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
description: Maximum value
|
||||
x-kubernetes-int-or-string: true
|
||||
min:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
description: Minimum value
|
||||
x-kubernetes-int-or-string: true
|
||||
type: object
|
||||
name:
|
||||
description: Name of the metric
|
||||
type: string
|
||||
templateRef:
|
||||
description: TemplateRef references a metric template object
|
||||
properties:
|
||||
apiVersion:
|
||||
description: APIVersion of the referenced object.
|
||||
type: string
|
||||
kind:
|
||||
description: Kind of the referenced object.
|
||||
type: string
|
||||
name:
|
||||
description: Name of the referenced object.
|
||||
type: string
|
||||
uid:
|
||||
description: UID of the referenced object.
|
||||
type: string
|
||||
required:
|
||||
- apiVersion
|
||||
- kind
|
||||
- name
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
type: array
|
||||
numBatches:
|
||||
description: The number of batches, default = 1
|
||||
format: int32
|
||||
type: integer
|
||||
paused:
|
||||
description: Paused the rollout, default is false
|
||||
type: boolean
|
||||
rolloutBatches:
|
||||
description: The exact distribution among batches. its size has to be exactly the same as the NumBatches (if set) The total number cannot exceed the targetSize or the size of the source resource We will IGNORE the last batch's replica field if it's a percentage since round errors can lead to inaccurate sum We highly recommend to leave the last batch's replica field empty
|
||||
items:
|
||||
description: RolloutBatch is used to describe how the each batch rollout should be
|
||||
properties:
|
||||
batchRolloutWebhooks:
|
||||
description: RolloutWebhooks provides a way for the batch rollout to interact with an external process
|
||||
items:
|
||||
description: RolloutWebhook holds the reference to external checks used for canary analysis
|
||||
properties:
|
||||
expectedStatus:
|
||||
description: ExpectedStatus contains all the expected http status code that we will accept as success
|
||||
items:
|
||||
type: integer
|
||||
type: array
|
||||
metadata:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: Metadata (key-value pairs) for this webhook
|
||||
type: object
|
||||
method:
|
||||
description: Method the HTTP call method, default is POST
|
||||
type: string
|
||||
name:
|
||||
description: Name of this webhook
|
||||
type: string
|
||||
type:
|
||||
description: Type of this webhook
|
||||
type: string
|
||||
url:
|
||||
description: URL address of this webhook
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
- type
|
||||
- url
|
||||
type: object
|
||||
type: array
|
||||
canaryMetric:
|
||||
description: CanaryMetric provides a way for the batch rollout process to automatically check certain metrics before moving to the next batch
|
||||
items:
|
||||
description: CanaryMetric holds the reference to metrics used for canary analysis
|
||||
properties:
|
||||
interval:
|
||||
description: Interval represents the windows size
|
||||
type: string
|
||||
metricsRange:
|
||||
description: Range value accepted for this metric
|
||||
properties:
|
||||
max:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
description: Maximum value
|
||||
x-kubernetes-int-or-string: true
|
||||
min:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
description: Minimum value
|
||||
x-kubernetes-int-or-string: true
|
||||
type: object
|
||||
name:
|
||||
description: Name of the metric
|
||||
type: string
|
||||
templateRef:
|
||||
description: TemplateRef references a metric template object
|
||||
properties:
|
||||
apiVersion:
|
||||
description: APIVersion of the referenced object.
|
||||
type: string
|
||||
kind:
|
||||
description: Kind of the referenced object.
|
||||
type: string
|
||||
name:
|
||||
description: Name of the referenced object.
|
||||
type: string
|
||||
uid:
|
||||
description: UID of the referenced object.
|
||||
type: string
|
||||
required:
|
||||
- apiVersion
|
||||
- kind
|
||||
- name
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
type: array
|
||||
instanceInterval:
|
||||
description: The wait time, in seconds, between instances upgrades, default = 0
|
||||
format: int32
|
||||
type: integer
|
||||
maxUnavailable:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
description: MaxUnavailable is the max allowed number of pods that is unavailable during the upgrade. We will mark the batch as ready as long as there are less or equal number of pods unavailable than this number. default = 0
|
||||
x-kubernetes-int-or-string: true
|
||||
podList:
|
||||
description: The list of Pods to get upgraded it is mutually exclusive with the Replicas field
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
replicas:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
description: 'Replicas is the number of pods to upgrade in this batch it can be an absolute number (ex: 5) or a percentage of total pods we will ignore the percentage of the last batch to just fill the gap it is mutually exclusive with the PodList field'
|
||||
x-kubernetes-int-or-string: true
|
||||
type: object
|
||||
type: array
|
||||
rolloutStrategy:
|
||||
description: RolloutStrategy defines strategies for the rollout plan
|
||||
type: string
|
||||
rolloutWebhooks:
|
||||
description: RolloutWebhooks provide a way for the rollout to interact with an external process
|
||||
items:
|
||||
description: RolloutWebhook holds the reference to external checks used for canary analysis
|
||||
properties:
|
||||
expectedStatus:
|
||||
description: ExpectedStatus contains all the expected http status code that we will accept as success
|
||||
items:
|
||||
type: integer
|
||||
type: array
|
||||
metadata:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: Metadata (key-value pairs) for this webhook
|
||||
type: object
|
||||
method:
|
||||
description: Method the HTTP call method, default is POST
|
||||
type: string
|
||||
name:
|
||||
description: Name of this webhook
|
||||
type: string
|
||||
type:
|
||||
description: Type of this webhook
|
||||
type: string
|
||||
url:
|
||||
description: URL address of this webhook
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
- type
|
||||
- url
|
||||
type: object
|
||||
type: array
|
||||
targetSize:
|
||||
description: The size of the target resource. The default is the same as the size of the source resource.
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
sourceApplicationName:
|
||||
description: SourceApplicationName contains the name of the applicationConfiguration that we need to upgrade from. it can be empty only when it's the first time to deploy the application
|
||||
type: string
|
||||
targetApplicationName:
|
||||
description: TargetAppRevisionName contains the name of the applicationConfiguration that we need to upgrade to. Here we use an applicationConfiguration as a revision of an application, thus the name alone is suffice
|
||||
type: string
|
||||
required:
|
||||
- rolloutPlan
|
||||
- targetApplicationName
|
||||
type: object
|
||||
status:
|
||||
description: AppRolloutStatus defines the observed state of AppRollout
|
||||
properties:
|
||||
LastSourceAppName:
|
||||
description: LastSourceAppName contains the name of the app that we need to upgrade from. We will restart the rollout if this is not the same as the spec
|
||||
type: string
|
||||
batchRollingState:
|
||||
description: BatchRollingState only meaningful when the Status is rolling
|
||||
type: string
|
||||
conditions:
|
||||
description: Conditions of the resource.
|
||||
items:
|
||||
description: A Condition that may apply to a resource.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: LastTransitionTime is the last time this condition transitioned from one status to another.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: A Message containing details about this condition's last transition from one status to another, if any.
|
||||
type: string
|
||||
reason:
|
||||
description: A Reason for this condition's last transition from one status to another.
|
||||
type: string
|
||||
status:
|
||||
description: Status of this condition; is it currently True, False, or Unknown?
|
||||
type: string
|
||||
type:
|
||||
description: Type of this condition. At most one of each condition type may apply to a resource at any point in time.
|
||||
type: string
|
||||
required:
|
||||
- lastTransitionTime
|
||||
- reason
|
||||
- status
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
currentBatch:
|
||||
description: The current batch the rollout is working on/blocked it starts from 0
|
||||
format: int32
|
||||
type: integer
|
||||
lastAppliedPodTemplateIdentifier:
|
||||
description: lastAppliedPodTemplateIdentifier is a string that uniquely represent the last pod template each workload type could use different ways to identify that so we cannot compare between resources We update this field only after a successful rollout
|
||||
type: string
|
||||
lastTargetAppName:
|
||||
description: LastTargetAppName contains the name of the app that we upgraded to We will restart the rollout if this is not the same as the spec
|
||||
type: string
|
||||
rollingState:
|
||||
description: RollingState is the Rollout State
|
||||
type: string
|
||||
targetGeneration:
|
||||
description: NewPodTemplateIdentifier is a string that uniquely represent the new pod template each workload type could use different ways to identify that so we cannot compare between resources
|
||||
type: string
|
||||
upgradedReadyReplicas:
|
||||
description: UpgradedReplicas is the number of Pods upgraded by the rollout controller that have a Ready Condition.
|
||||
format: int32
|
||||
type: integer
|
||||
upgradedReplicas:
|
||||
description: UpgradedReplicas is the number of Pods upgraded by the rollout controller
|
||||
format: int32
|
||||
type: integer
|
||||
required:
|
||||
- currentBatch
|
||||
- lastTargetAppName
|
||||
- rollingState
|
||||
- upgradedReadyReplicas
|
||||
- upgradedReplicas
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
@@ -0,0 +1,352 @@
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.2.4
|
||||
creationTimestamp: null
|
||||
name: approllouts.core.oam.dev
|
||||
spec:
|
||||
group: core.oam.dev
|
||||
names:
|
||||
categories:
|
||||
- oam
|
||||
kind: AppRollout
|
||||
listKind: AppRolloutList
|
||||
plural: approllouts
|
||||
singular: approllout
|
||||
scope: Namespaced
|
||||
subresources:
|
||||
status: {}
|
||||
validation:
|
||||
openAPIV3Schema:
|
||||
description: AppRollout is the Schema for the AppRollout API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: AppRolloutSpec defines how to describe an upgrade between different apps
|
||||
properties:
|
||||
componentList:
|
||||
description: 'The list of component to upgrade in the application. We only support single component application so far TODO: (RZ) Support multiple components in an application'
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
revertOnDelete:
|
||||
description: RevertOnDelete revert the rollout when the rollout CR is deleted It will remove the target app from the kubernetes if it's set to true
|
||||
type: boolean
|
||||
rolloutPlan:
|
||||
description: RolloutPlan is the details on how to rollout the resources
|
||||
properties:
|
||||
batchPartition:
|
||||
description: All pods in the batches up to the batchPartition (included) will have the target resource specification while the rest still have the source resource This is designed for the operators to manually rollout Default is the the number of batches which will rollout all the batches
|
||||
format: int32
|
||||
type: integer
|
||||
canaryMetric:
|
||||
description: CanaryMetric provides a way for the rollout process to automatically check certain metrics before complete the process
|
||||
items:
|
||||
description: CanaryMetric holds the reference to metrics used for canary analysis
|
||||
properties:
|
||||
interval:
|
||||
description: Interval represents the windows size
|
||||
type: string
|
||||
metricsRange:
|
||||
description: Range value accepted for this metric
|
||||
properties:
|
||||
max:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
description: Maximum value
|
||||
x-kubernetes-int-or-string: true
|
||||
min:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
description: Minimum value
|
||||
x-kubernetes-int-or-string: true
|
||||
type: object
|
||||
name:
|
||||
description: Name of the metric
|
||||
type: string
|
||||
templateRef:
|
||||
description: TemplateRef references a metric template object
|
||||
properties:
|
||||
apiVersion:
|
||||
description: APIVersion of the referenced object.
|
||||
type: string
|
||||
kind:
|
||||
description: Kind of the referenced object.
|
||||
type: string
|
||||
name:
|
||||
description: Name of the referenced object.
|
||||
type: string
|
||||
uid:
|
||||
description: UID of the referenced object.
|
||||
type: string
|
||||
required:
|
||||
- apiVersion
|
||||
- kind
|
||||
- name
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
type: array
|
||||
numBatches:
|
||||
description: The number of batches, default = 1
|
||||
format: int32
|
||||
type: integer
|
||||
paused:
|
||||
description: Paused the rollout, default is false
|
||||
type: boolean
|
||||
rolloutBatches:
|
||||
description: The exact distribution among batches. its size has to be exactly the same as the NumBatches (if set) The total number cannot exceed the targetSize or the size of the source resource We will IGNORE the last batch's replica field if it's a percentage since round errors can lead to inaccurate sum We highly recommend to leave the last batch's replica field empty
|
||||
items:
|
||||
description: RolloutBatch is used to describe how the each batch rollout should be
|
||||
properties:
|
||||
batchRolloutWebhooks:
|
||||
description: RolloutWebhooks provides a way for the batch rollout to interact with an external process
|
||||
items:
|
||||
description: RolloutWebhook holds the reference to external checks used for canary analysis
|
||||
properties:
|
||||
expectedStatus:
|
||||
description: ExpectedStatus contains all the expected http status code that we will accept as success
|
||||
items:
|
||||
type: integer
|
||||
type: array
|
||||
metadata:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: Metadata (key-value pairs) for this webhook
|
||||
type: object
|
||||
method:
|
||||
description: Method the HTTP call method, default is POST
|
||||
type: string
|
||||
name:
|
||||
description: Name of this webhook
|
||||
type: string
|
||||
type:
|
||||
description: Type of this webhook
|
||||
type: string
|
||||
url:
|
||||
description: URL address of this webhook
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
- type
|
||||
- url
|
||||
type: object
|
||||
type: array
|
||||
canaryMetric:
|
||||
description: CanaryMetric provides a way for the batch rollout process to automatically check certain metrics before moving to the next batch
|
||||
items:
|
||||
description: CanaryMetric holds the reference to metrics used for canary analysis
|
||||
properties:
|
||||
interval:
|
||||
description: Interval represents the windows size
|
||||
type: string
|
||||
metricsRange:
|
||||
description: Range value accepted for this metric
|
||||
properties:
|
||||
max:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
description: Maximum value
|
||||
x-kubernetes-int-or-string: true
|
||||
min:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
description: Minimum value
|
||||
x-kubernetes-int-or-string: true
|
||||
type: object
|
||||
name:
|
||||
description: Name of the metric
|
||||
type: string
|
||||
templateRef:
|
||||
description: TemplateRef references a metric template object
|
||||
properties:
|
||||
apiVersion:
|
||||
description: APIVersion of the referenced object.
|
||||
type: string
|
||||
kind:
|
||||
description: Kind of the referenced object.
|
||||
type: string
|
||||
name:
|
||||
description: Name of the referenced object.
|
||||
type: string
|
||||
uid:
|
||||
description: UID of the referenced object.
|
||||
type: string
|
||||
required:
|
||||
- apiVersion
|
||||
- kind
|
||||
- name
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
type: array
|
||||
instanceInterval:
|
||||
description: The wait time, in seconds, between instances upgrades, default = 0
|
||||
format: int32
|
||||
type: integer
|
||||
maxUnavailable:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
description: MaxUnavailable is the max allowed number of pods that is unavailable during the upgrade. We will mark the batch as ready as long as there are less or equal number of pods unavailable than this number. default = 0
|
||||
x-kubernetes-int-or-string: true
|
||||
podList:
|
||||
description: The list of Pods to get upgraded it is mutually exclusive with the Replicas field
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
replicas:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
description: 'Replicas is the number of pods to upgrade in this batch it can be an absolute number (ex: 5) or a percentage of total pods we will ignore the percentage of the last batch to just fill the gap it is mutually exclusive with the PodList field'
|
||||
x-kubernetes-int-or-string: true
|
||||
type: object
|
||||
type: array
|
||||
rolloutStrategy:
|
||||
description: RolloutStrategy defines strategies for the rollout plan
|
||||
type: string
|
||||
rolloutWebhooks:
|
||||
description: RolloutWebhooks provide a way for the rollout to interact with an external process
|
||||
items:
|
||||
description: RolloutWebhook holds the reference to external checks used for canary analysis
|
||||
properties:
|
||||
expectedStatus:
|
||||
description: ExpectedStatus contains all the expected http status code that we will accept as success
|
||||
items:
|
||||
type: integer
|
||||
type: array
|
||||
metadata:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: Metadata (key-value pairs) for this webhook
|
||||
type: object
|
||||
method:
|
||||
description: Method the HTTP call method, default is POST
|
||||
type: string
|
||||
name:
|
||||
description: Name of this webhook
|
||||
type: string
|
||||
type:
|
||||
description: Type of this webhook
|
||||
type: string
|
||||
url:
|
||||
description: URL address of this webhook
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
- type
|
||||
- url
|
||||
type: object
|
||||
type: array
|
||||
targetSize:
|
||||
description: The size of the target resource. The default is the same as the size of the source resource.
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
sourceApplicationName:
|
||||
description: SourceApplicationName contains the name of the applicationConfiguration that we need to upgrade from. it can be empty only when it's the first time to deploy the application
|
||||
type: string
|
||||
targetApplicationName:
|
||||
description: TargetAppRevisionName contains the name of the applicationConfiguration that we need to upgrade to. Here we use an applicationConfiguration as a revision of an application, thus the name alone is suffice
|
||||
type: string
|
||||
required:
|
||||
- rolloutPlan
|
||||
- targetApplicationName
|
||||
type: object
|
||||
status:
|
||||
description: AppRolloutStatus defines the observed state of AppRollout
|
||||
properties:
|
||||
LastSourceAppName:
|
||||
description: LastSourceAppName contains the name of the app that we need to upgrade from. We will restart the rollout if this is not the same as the spec
|
||||
type: string
|
||||
batchRollingState:
|
||||
description: BatchRollingState only meaningful when the Status is rolling
|
||||
type: string
|
||||
conditions:
|
||||
description: Conditions of the resource.
|
||||
items:
|
||||
description: A Condition that may apply to a resource.
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: LastTransitionTime is the last time this condition transitioned from one status to another.
|
||||
format: date-time
|
||||
type: string
|
||||
message:
|
||||
description: A Message containing details about this condition's last transition from one status to another, if any.
|
||||
type: string
|
||||
reason:
|
||||
description: A Reason for this condition's last transition from one status to another.
|
||||
type: string
|
||||
status:
|
||||
description: Status of this condition; is it currently True, False, or Unknown?
|
||||
type: string
|
||||
type:
|
||||
description: Type of this condition. At most one of each condition type may apply to a resource at any point in time.
|
||||
type: string
|
||||
required:
|
||||
- lastTransitionTime
|
||||
- reason
|
||||
- status
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
currentBatch:
|
||||
description: The current batch the rollout is working on/blocked it starts from 0
|
||||
format: int32
|
||||
type: integer
|
||||
lastAppliedPodTemplateIdentifier:
|
||||
description: lastAppliedPodTemplateIdentifier is a string that uniquely represent the last pod template each workload type could use different ways to identify that so we cannot compare between resources We update this field only after a successful rollout
|
||||
type: string
|
||||
lastTargetAppName:
|
||||
description: LastTargetAppName contains the name of the app that we upgraded to We will restart the rollout if this is not the same as the spec
|
||||
type: string
|
||||
rollingState:
|
||||
description: RollingState is the Rollout State
|
||||
type: string
|
||||
targetGeneration:
|
||||
description: NewPodTemplateIdentifier is a string that uniquely represent the new pod template each workload type could use different ways to identify that so we cannot compare between resources
|
||||
type: string
|
||||
upgradedReadyReplicas:
|
||||
description: UpgradedReplicas is the number of Pods upgraded by the rollout controller that have a Ready Condition.
|
||||
format: int32
|
||||
type: integer
|
||||
upgradedReplicas:
|
||||
description: UpgradedReplicas is the number of Pods upgraded by the rollout controller
|
||||
format: int32
|
||||
type: integer
|
||||
required:
|
||||
- currentBatch
|
||||
- lastTargetAppName
|
||||
- rollingState
|
||||
- upgradedReadyReplicas
|
||||
- upgradedReplicas
|
||||
type: object
|
||||
type: object
|
||||
version: v1alpha2
|
||||
versions:
|
||||
- name: v1alpha2
|
||||
served: true
|
||||
storage: true
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
@@ -1653,7 +1653,7 @@ func TestIsControlledByApp(t *testing.T) {
|
||||
// still true when it's not the only the controller
|
||||
ac.OwnerReferences = append(ac.OwnerReferences, metav1.OwnerReference{
|
||||
APIVersion: v1alpha2.SchemeGroupVersion.String(),
|
||||
Kind: v1alpha2.ApplicationDeploymentKind,
|
||||
Kind: v1alpha2.AppRolloutKind,
|
||||
Controller: pointer.BoolPtr(true),
|
||||
})
|
||||
assert.True(t, isControlledByApp(ac))
|
||||
|
||||
@@ -37,14 +37,14 @@ type Reconciler struct {
|
||||
Scheme *runtime.Scheme
|
||||
}
|
||||
|
||||
// +kubebuilder:rbac:groups=core.oam.dev,resources=applicationdeployments,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=core.oam.dev,resources=applicationdeployments/status,verbs=get;update;patch
|
||||
// +kubebuilder:rbac:groups=core.oam.dev,resources=approllouts,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=core.oam.dev,resources=approllouts/status,verbs=get;update;patch
|
||||
// +kubebuilder:rbac:groups=core.oam.dev,resources=applications,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=core.oam.dev,resources=applications/status,verbs=get;update;patch
|
||||
|
||||
// Reconcile is the main logic of applicationdeployment controller
|
||||
func (r *Reconciler) Reconcile(req ctrl.Request) (res reconcile.Result, retErr error) {
|
||||
var appDeploy oamv1alpha2.ApplicationDeployment
|
||||
var appRollout oamv1alpha2.AppRollout
|
||||
ctx, cancel := context.WithTimeout(context.TODO(), reconcileTimeOut)
|
||||
defer cancel()
|
||||
|
||||
@@ -62,23 +62,23 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (res reconcile.Result, retErr e
|
||||
}
|
||||
}()
|
||||
|
||||
if err := r.Get(ctx, req.NamespacedName, &appDeploy); err != nil {
|
||||
if err := r.Get(ctx, req.NamespacedName, &appRollout); err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
klog.InfoS("application deployment does not exist", "appDeploy", klog.KRef(req.Namespace, req.Name))
|
||||
klog.InfoS("application deployment does not exist", "appRollout", klog.KRef(req.Namespace, req.Name))
|
||||
}
|
||||
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||
}
|
||||
klog.InfoS("Start to reconcile ", "application deployment", klog.KObj(&appDeploy))
|
||||
klog.InfoS("Start to reconcile ", "application deployment", klog.KObj(&appRollout))
|
||||
|
||||
// TODO: check if the target/source has changed
|
||||
r.handleFinalizer(&appDeploy)
|
||||
r.handleFinalizer(&appRollout)
|
||||
|
||||
ctx = oamutil.SetNnamespaceInCtx(ctx, appDeploy.Namespace)
|
||||
ctx = oamutil.SetNnamespaceInCtx(ctx, appRollout.Namespace)
|
||||
|
||||
// Get the target application
|
||||
var targetApp oamv1alpha2.ApplicationConfiguration
|
||||
sourceApp := &oamv1alpha2.ApplicationConfiguration{}
|
||||
targetAppName := appDeploy.Spec.TargetApplicationName
|
||||
targetAppName := appRollout.Spec.TargetAppRevisionName
|
||||
if err := r.Get(ctx, ktypes.NamespacedName{Namespace: req.Namespace, Name: targetAppName},
|
||||
&targetApp); err != nil {
|
||||
klog.ErrorS(err, "cannot locate target application", "target application",
|
||||
@@ -87,7 +87,7 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (res reconcile.Result, retErr e
|
||||
}
|
||||
|
||||
// Get the source application
|
||||
sourceAppName := appDeploy.Spec.SourceApplicationName
|
||||
sourceAppName := appRollout.Spec.SourceApplicationName
|
||||
if sourceAppName == "" {
|
||||
klog.Info("source app fields not filled, we assume it is deployed for the first time")
|
||||
sourceApp = nil
|
||||
@@ -97,11 +97,11 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (res reconcile.Result, retErr e
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
targetWorkload, sourceWorkload, err := r.extractWorkloads(ctx, appDeploy.Spec.ComponentList, &targetApp, sourceApp)
|
||||
targetWorkload, sourceWorkload, err := r.extractWorkloads(ctx, appRollout.Spec.ComponentList, &targetApp, sourceApp)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "cannot fetch the workloads to upgrade", "target application",
|
||||
klog.KRef(req.Namespace, targetAppName), "source application", klog.KRef(req.Namespace, sourceAppName),
|
||||
"commonComponent", appDeploy.Spec.ComponentList)
|
||||
"commonComponent", appRollout.Spec.ComponentList)
|
||||
return ctrl.Result{RequeueAfter: 5 * time.Second}, client.IgnoreNotFound(err)
|
||||
}
|
||||
klog.InfoS("get the target workload we need to work on", "targetWorkload", klog.KObj(targetWorkload))
|
||||
@@ -111,11 +111,11 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (res reconcile.Result, retErr e
|
||||
}
|
||||
|
||||
// reconcile the rollout part of the spec given the target and source workload
|
||||
rolloutPlanController := rollout.NewRolloutPlanController(r, &appDeploy, r.record,
|
||||
&appDeploy.Spec.RolloutPlan, &appDeploy.Status.RolloutStatus, targetWorkload, sourceWorkload)
|
||||
rolloutPlanController := rollout.NewRolloutPlanController(r, &appRollout, r.record,
|
||||
&appRollout.Spec.RolloutPlan, &appRollout.Status.RolloutStatus, targetWorkload, sourceWorkload)
|
||||
result, rolloutStatus := rolloutPlanController.Reconcile(ctx)
|
||||
// make sure that the new status is copied back
|
||||
appDeploy.Status.RolloutStatus = *rolloutStatus
|
||||
appRollout.Status.RolloutStatus = *rolloutStatus
|
||||
if rolloutStatus.RollingState == v1alpha1.RolloutSucceedState {
|
||||
// remove the rollout annotation so that the target appConfig controller can take over the rest of the work
|
||||
oamutil.RemoveAnnotations(&targetApp, []string{oam.AnnotationAppRollout})
|
||||
@@ -125,29 +125,29 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (res reconcile.Result, retErr e
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
}
|
||||
// update the appDeploy status
|
||||
return result, r.updateStatus(ctx, &appDeploy)
|
||||
// update the appRollout status
|
||||
return result, r.updateStatus(ctx, &appRollout)
|
||||
}
|
||||
|
||||
// UpdateStatus updates v1alpha2.ApplicationDeployment's Status with retry.RetryOnConflict
|
||||
func (r *Reconciler) updateStatus(ctx context.Context, app *oamv1alpha2.ApplicationDeployment, opts ...client.UpdateOption) error {
|
||||
status := app.DeepCopy().Status
|
||||
// UpdateStatus updates v1alpha2.AppRollout's Status with retry.RetryOnConflict
|
||||
func (r *Reconciler) updateStatus(ctx context.Context, appRollout *oamv1alpha2.AppRollout, opts ...client.UpdateOption) error {
|
||||
status := appRollout.DeepCopy().Status
|
||||
return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) {
|
||||
if err = r.Get(ctx, client.ObjectKey{Namespace: app.Namespace, Name: app.Name}, app); err != nil {
|
||||
if err = r.Get(ctx, client.ObjectKey{Namespace: appRollout.Namespace, Name: appRollout.Name}, appRollout); err != nil {
|
||||
return
|
||||
}
|
||||
app.Status = status
|
||||
return r.Status().Update(ctx, app, opts...)
|
||||
appRollout.Status = status
|
||||
return r.Status().Update(ctx, appRollout, opts...)
|
||||
})
|
||||
}
|
||||
|
||||
func (r *Reconciler) handleFinalizer(appDeploy *oamv1alpha2.ApplicationDeployment) {
|
||||
if appDeploy.DeletionTimestamp.IsZero() {
|
||||
if !slice.ContainsString(appDeploy.Finalizers, appDeployFinalizer, nil) {
|
||||
func (r *Reconciler) handleFinalizer(appRollout *oamv1alpha2.AppRollout) {
|
||||
if appRollout.DeletionTimestamp.IsZero() {
|
||||
if !slice.ContainsString(appRollout.Finalizers, appDeployFinalizer, nil) {
|
||||
// TODO: add finalizer
|
||||
klog.Info("add finalizer")
|
||||
}
|
||||
} else if slice.ContainsString(appDeploy.Finalizers, appDeployFinalizer, nil) {
|
||||
} else if slice.ContainsString(appRollout.Finalizers, appDeployFinalizer, nil) {
|
||||
// TODO: perform finalize
|
||||
klog.Info("perform clean up")
|
||||
}
|
||||
@@ -158,7 +158,7 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||
r.record = event.NewAPIRecorder(mgr.GetEventRecorderFor("ApplicationDeployment")).
|
||||
WithAnnotations("controller", "ApplicationDeployment")
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
For(&oamv1alpha2.ApplicationDeployment{}).
|
||||
For(&oamv1alpha2.AppRollout{}).
|
||||
Owns(&oamv1alpha2.Application{}).
|
||||
Complete(r)
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ var _ admission.Handler = &MutatingHandler{}
|
||||
|
||||
// Handle handles admission requests.
|
||||
func (h *MutatingHandler) Handle(ctx context.Context, req admission.Request) admission.Response {
|
||||
obj := &v1alpha2.ApplicationDeployment{}
|
||||
obj := &v1alpha2.AppRollout{}
|
||||
|
||||
err := h.Decoder.Decode(req, obj)
|
||||
if err != nil {
|
||||
@@ -52,7 +52,7 @@ func (h *MutatingHandler) Handle(ctx context.Context, req admission.Request) adm
|
||||
}
|
||||
|
||||
// DefaultApplicationDeployment will set the default value for the ApplicationDeployment
|
||||
func DefaultApplicationDeployment(obj *v1alpha2.ApplicationDeployment) {
|
||||
func DefaultApplicationDeployment(obj *v1alpha2.AppRollout) {
|
||||
klog.InfoS("default", "name", obj.Name)
|
||||
if obj.Spec.RevertOnDelete == nil {
|
||||
klog.V(common.LogDebug).Info("default RevertOnDelete as false")
|
||||
|
||||
@@ -27,7 +27,7 @@ var _ admission.Handler = &ValidatingHandler{}
|
||||
|
||||
// Handle handles admission requests.
|
||||
func (h *ValidatingHandler) Handle(ctx context.Context, req admission.Request) admission.Response {
|
||||
obj := &v1alpha2.ApplicationDeployment{}
|
||||
obj := &v1alpha2.AppRollout{}
|
||||
|
||||
err := h.Decoder.Decode(req, obj)
|
||||
if err != nil {
|
||||
@@ -42,7 +42,7 @@ func (h *ValidatingHandler) Handle(ctx context.Context, req admission.Request) a
|
||||
return admission.Errored(http.StatusUnprocessableEntity, allErrs.ToAggregate())
|
||||
}
|
||||
case admissionv1beta1.Update:
|
||||
oldObj := &v1alpha2.ApplicationDeployment{}
|
||||
oldObj := &v1alpha2.AppRollout{}
|
||||
if err := h.Decoder.DecodeRaw(req.AdmissionRequest.OldObject, oldObj); err != nil {
|
||||
return admission.Errored(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
@@ -14,13 +14,13 @@ import (
|
||||
)
|
||||
|
||||
// ValidateCreate validates the ApplicationDeployment on creation
|
||||
func (h *ValidatingHandler) ValidateCreate(appDeploy *v1alpha2.ApplicationDeployment) field.ErrorList {
|
||||
klog.InfoS("validate create", "name", appDeploy.Name)
|
||||
allErrs := apimachineryvalidation.ValidateObjectMeta(&appDeploy.ObjectMeta, true,
|
||||
func (h *ValidatingHandler) ValidateCreate(appRollout *v1alpha2.AppRollout) field.ErrorList {
|
||||
klog.InfoS("validate create", "name", appRollout.Name)
|
||||
allErrs := apimachineryvalidation.ValidateObjectMeta(&appRollout.ObjectMeta, true,
|
||||
apimachineryvalidation.NameIsDNSSubdomain, field.NewPath("metadata"))
|
||||
|
||||
fldPath := field.NewPath("spec")
|
||||
target := appDeploy.Spec.TargetApplicationName
|
||||
target := appRollout.Spec.TargetAppRevisionName
|
||||
if len(target) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("targetApplicationName"),
|
||||
"target application name cannot be empty"))
|
||||
@@ -29,31 +29,31 @@ func (h *ValidatingHandler) ValidateCreate(appDeploy *v1alpha2.ApplicationDeploy
|
||||
}
|
||||
|
||||
var targetApp, sourceApp v1alpha2.ApplicationConfiguration
|
||||
targetAppName := appDeploy.Spec.TargetApplicationName
|
||||
if err := h.Get(context.Background(), ktypes.NamespacedName{Namespace: appDeploy.Namespace, Name: targetAppName},
|
||||
targetAppName := appRollout.Spec.TargetAppRevisionName
|
||||
if err := h.Get(context.Background(), ktypes.NamespacedName{Namespace: appRollout.Namespace, Name: targetAppName},
|
||||
&targetApp); err != nil {
|
||||
klog.ErrorS(err, "cannot locate target application", "target application",
|
||||
klog.KRef(appDeploy.Namespace, targetAppName))
|
||||
klog.KRef(appRollout.Namespace, targetAppName))
|
||||
allErrs = append(allErrs, field.NotFound(fldPath.Child("targetApplicationName"), targetAppName))
|
||||
// can't continue without target
|
||||
return allErrs
|
||||
}
|
||||
sourceAppName := appDeploy.Spec.SourceApplicationName
|
||||
sourceAppName := appRollout.Spec.SourceApplicationName
|
||||
if sourceAppName != "" {
|
||||
if err := h.Get(context.Background(), ktypes.NamespacedName{Namespace: appDeploy.Namespace, Name: sourceAppName},
|
||||
if err := h.Get(context.Background(), ktypes.NamespacedName{Namespace: appRollout.Namespace, Name: sourceAppName},
|
||||
&sourceApp); err != nil {
|
||||
klog.ErrorS(err, "cannot locate source application", "source application",
|
||||
klog.KRef(appDeploy.Namespace, sourceAppName))
|
||||
klog.KRef(appRollout.Namespace, sourceAppName))
|
||||
allErrs = append(allErrs, field.NotFound(fldPath.Child("sourceApplicationName"), sourceAppName))
|
||||
}
|
||||
}
|
||||
|
||||
// validate the component spec
|
||||
allErrs = append(allErrs, validateComponent(appDeploy.Spec.ComponentList, &targetApp, &sourceApp,
|
||||
allErrs = append(allErrs, validateComponent(appRollout.Spec.ComponentList, &targetApp, &sourceApp,
|
||||
fldPath.Child("componentList"))...)
|
||||
|
||||
// validate the rollout plan spec
|
||||
allErrs = append(allErrs, rollout.ValidateCreate(&appDeploy.Spec.RolloutPlan, fldPath.Child("rolloutPlan"))...)
|
||||
allErrs = append(allErrs, rollout.ValidateCreate(&appRollout.Spec.RolloutPlan, fldPath.Child("rolloutPlan"))...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ func validateComponent(componentList []string, targetApp, sourceApp *v1alpha2.Ap
|
||||
}
|
||||
|
||||
// ValidateUpdate validates the ApplicationDeployment on update
|
||||
func (h *ValidatingHandler) ValidateUpdate(new, old *v1alpha2.ApplicationDeployment) field.ErrorList {
|
||||
func (h *ValidatingHandler) ValidateUpdate(new, old *v1alpha2.AppRollout) field.ErrorList {
|
||||
klog.InfoS("validate update", "name", new.Name)
|
||||
errList := h.ValidateCreate(new)
|
||||
if len(errList) > 0 {
|
||||
|
||||
@@ -140,24 +140,24 @@ var _ = Describe("Test Rolling out Application", func() {
|
||||
Expect(kc.Spec.UpdateStrategy.Paused).Should(BeTrue())
|
||||
|
||||
By("Apply the application rollout that stops after two batches")
|
||||
var appDeploy v1alpha2.ApplicationDeployment
|
||||
Expect(readYaml("testdata/rollout/app-deploy-pause.yaml", &appDeploy)).Should(BeNil())
|
||||
appDeploy.Namespace = namespace
|
||||
Expect(k8sClient.Create(ctx, &appDeploy)).Should(Succeed())
|
||||
var appRollout v1alpha2.AppRollout
|
||||
Expect(readYaml("testdata/rollout/app-deploy-pause.yaml", &appRollout)).Should(BeNil())
|
||||
appRollout.Namespace = namespace
|
||||
Expect(k8sClient.Create(ctx, &appRollout)).Should(Succeed())
|
||||
|
||||
By("Wait for the rollout phase change to rolling in batches")
|
||||
Eventually(
|
||||
func() oamstd.RollingState {
|
||||
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: appDeploy.Name}, &appDeploy)
|
||||
return appDeploy.Status.RollingState
|
||||
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: appRollout.Name}, &appRollout)
|
||||
return appRollout.Status.RollingState
|
||||
},
|
||||
time.Second*60, time.Millisecond*500).Should(BeEquivalentTo(oamstd.RollingInBatchesState))
|
||||
|
||||
By("Wait for rollout to finish two batches")
|
||||
Eventually(
|
||||
func() int32 {
|
||||
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: appDeploy.Name}, &appDeploy)
|
||||
return appDeploy.Status.CurrentBatch
|
||||
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: appRollout.Name}, &appRollout)
|
||||
return appRollout.Status.CurrentBatch
|
||||
},
|
||||
time.Second*60, time.Millisecond*500).Should(BeEquivalentTo(1))
|
||||
|
||||
@@ -165,15 +165,15 @@ var _ = Describe("Test Rolling out Application", func() {
|
||||
// wait for the batch to be ready
|
||||
Eventually(
|
||||
func() oamstd.BatchRollingState {
|
||||
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: appDeploy.Name}, &appDeploy)
|
||||
return appDeploy.Status.BatchRollingState
|
||||
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: appRollout.Name}, &appRollout)
|
||||
return appRollout.Status.BatchRollingState
|
||||
},
|
||||
time.Second*60, time.Millisecond*500).Should(Equal(oamstd.BatchReadyState))
|
||||
// wait for 30 seconds, it should still be at 1
|
||||
time.Sleep(30 * time.Second)
|
||||
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: appDeploy.Name}, &appDeploy)
|
||||
Expect(appDeploy.Status.CurrentBatch).Should(BeEquivalentTo(1))
|
||||
Expect(appDeploy.Status.BatchRollingState).Should(BeEquivalentTo(oamstd.BatchReadyState))
|
||||
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: appRollout.Name}, &appRollout)
|
||||
Expect(appRollout.Status.CurrentBatch).Should(BeEquivalentTo(1))
|
||||
Expect(appRollout.Status.BatchRollingState).Should(BeEquivalentTo(oamstd.BatchReadyState))
|
||||
|
||||
Expect(k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: workloadName},
|
||||
&kc)).ShouldNot(HaveOccurred())
|
||||
@@ -181,15 +181,15 @@ var _ = Describe("Test Rolling out Application", func() {
|
||||
Expect(kc.Status.UpdatedReadyReplicas).Should(BeEquivalentTo(3))
|
||||
|
||||
By("Finish the application rollout")
|
||||
Expect(readYaml("testdata/rollout/app-deploy-finish.yaml", &appDeploy)).Should(BeNil())
|
||||
appDeploy.Namespace = namespace
|
||||
Expect(k8sClient.Update(ctx, &appDeploy)).Should(Succeed())
|
||||
Expect(readYaml("testdata/rollout/app-deploy-finish.yaml", &appRollout)).Should(BeNil())
|
||||
appRollout.Namespace = namespace
|
||||
Expect(k8sClient.Update(ctx, &appRollout)).Should(Succeed())
|
||||
|
||||
By("Wait for the rollout phase change to succeeded")
|
||||
Eventually(
|
||||
func() oamstd.RollingState {
|
||||
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: appDeploy.Name}, &appDeploy)
|
||||
return appDeploy.Status.RollingState
|
||||
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: appRollout.Name}, &appRollout)
|
||||
return appRollout.Status.RollingState
|
||||
},
|
||||
time.Second*60, time.Millisecond*500).Should(Equal(oamstd.RolloutSucceedState))
|
||||
|
||||
@@ -199,7 +199,7 @@ var _ = Describe("Test Rolling out Application", func() {
|
||||
Expect(kc.Status.UpdatedReplicas).Should(BeEquivalentTo(5))
|
||||
Expect(kc.Status.UpdatedReadyReplicas).Should(BeEquivalentTo(5))
|
||||
// Clean up
|
||||
k8sClient.Delete(ctx, &appDeploy)
|
||||
k8sClient.Delete(ctx, &appRollout)
|
||||
k8sClient.Delete(ctx, &appConfig2)
|
||||
k8sClient.Delete(ctx, &appConfig1)
|
||||
k8sClient.Delete(ctx, &app)
|
||||
|
||||
Reference in New Issue
Block a user