From 960385be2a36e25498d3e42a066c99e1f37a8202 Mon Sep 17 00:00:00 2001 From: Alena Varkockova Date: Tue, 6 Oct 2020 12:17:04 +0200 Subject: [PATCH] Implement Ready condition for Instance type Signed-off-by: Alena Varkockova --- config/crds/kudo.dev_instances.yaml | 43 ++++++++ pkg/apis/kudo/v1beta1/instance_types.go | 1 + .../kudo/v1beta1/instance_types_helpers.go | 28 +++++ .../kudo/v1beta1/zz_generated.deepcopy.go | 12 ++- .../instance/instance_controller.go | 34 +++++- pkg/kubernetes/status/readiness.go | 100 ++++++++++++++++++ pkg/kubernetes/status/readiness_test.go | 96 +++++++++++++++++ .../cmd/testdata/deploy-kudo-ns.yaml.golden | 43 ++++++++ .../cmd/testdata/deploy-kudo-sa.yaml.golden | 43 ++++++++ .../cmd/testdata/deploy-kudo.json.golden | 54 ++++++++++ .../cmd/testdata/deploy-kudo.yaml.golden | 43 ++++++++ pkg/kudoctl/kudoinit/crd/bindata.go | 2 +- test/e2e/readiness/00-assert.yaml | 16 +++ test/e2e/readiness/00-install.yaml | 5 + test/e2e/readiness/01-assert.yaml | 8 ++ test/e2e/readiness/01-updatedeployment.yaml | 19 ++++ .../readiness/first-operator/operator.yaml | 25 +++++ test/e2e/readiness/first-operator/params.yaml | 5 + .../first-operator/templates/deployment.yaml | 19 ++++ 19 files changed, 591 insertions(+), 5 deletions(-) create mode 100644 pkg/kubernetes/status/readiness.go create mode 100644 pkg/kubernetes/status/readiness_test.go create mode 100644 test/e2e/readiness/00-assert.yaml create mode 100644 test/e2e/readiness/00-install.yaml create mode 100644 test/e2e/readiness/01-assert.yaml create mode 100644 test/e2e/readiness/01-updatedeployment.yaml create mode 100644 test/e2e/readiness/first-operator/operator.yaml create mode 100644 test/e2e/readiness/first-operator/params.yaml create mode 100644 test/e2e/readiness/first-operator/templates/deployment.yaml diff --git a/config/crds/kudo.dev_instances.yaml b/config/crds/kudo.dev_instances.yaml index 806f2ca8f..1fd81cc3d 100644 --- a/config/crds/kudo.dev_instances.yaml +++ b/config/crds/kudo.dev_instances.yaml @@ -77,6 +77,49 @@ spec: status: description: InstanceStatus defines the observed state of Instance properties: + conditions: + items: + description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array planStatus: additionalProperties: description: "PlanStatus is representing status of a plan \n These are valid states and transitions \n | Never executed | | v | Error |<------>| Pending | ^ | | v | +-------+--------+ | +-------+--------+ | | v v | Fatal error | | Complete |" diff --git a/pkg/apis/kudo/v1beta1/instance_types.go b/pkg/apis/kudo/v1beta1/instance_types.go index 415c719f1..00787142c 100644 --- a/pkg/apis/kudo/v1beta1/instance_types.go +++ b/pkg/apis/kudo/v1beta1/instance_types.go @@ -55,6 +55,7 @@ type PlanExecution struct { type InstanceStatus struct { // slice would be enough here but we cannot use slice because order of sequence in yaml is considered significant while here it's not PlanStatus map[string]PlanStatus `json:"planStatus,omitempty"` + Conditions []metav1.Condition `json:"conditions,omitempty"` } // PlanStatus is representing status of a plan diff --git a/pkg/apis/kudo/v1beta1/instance_types_helpers.go b/pkg/apis/kudo/v1beta1/instance_types_helpers.go index 7e6ded30c..c301326aa 100644 --- a/pkg/apis/kudo/v1beta1/instance_types_helpers.go +++ b/pkg/apis/kudo/v1beta1/instance_types_helpers.go @@ -5,6 +5,8 @@ import ( "fmt" "log" + "k8s.io/apimachinery/pkg/api/meta" + "github.com/thoas/go-funk" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -70,6 +72,7 @@ func (i *Instance) NoPlanEverExecuted() bool { } // UpdateInstanceStatus updates `Status.PlanStatus` and `Status.AggregatedStatus` property based on the given plan +// also updates Ready condition for finished plans func (i *Instance) UpdateInstanceStatus(ps *PlanStatus, updatedTimestamp *metav1.Time) { for k, v := range i.Status.PlanStatus { if v.Name == ps.Name { @@ -78,6 +81,9 @@ func (i *Instance) UpdateInstanceStatus(ps *PlanStatus, updatedTimestamp *metav1 i.Spec.PlanExecution.Status = ps.Status } } + if i.Spec.PlanExecution.Status.IsFinished() { + i.SetReadinessTrue("") + } } // ResetPlanStatus method resets a PlanStatus for a passed plan name and instance. Plan/phase/step statuses @@ -196,6 +202,28 @@ func (i *Instance) IsTopLevelInstance() bool { return !i.IsChildInstance() } +const ( + planInProgressReason = "PlanInProgress" + resourceNotReadyReason = "ResourceNotReady" + readyConditionType = "Ready" +) + +func (i *Instance) SetReadinessTrue(msg string) { + condition := metav1.Condition{Type: readyConditionType, Status: metav1.ConditionTrue, Message: msg} + meta.SetStatusCondition(&i.Status.Conditions, condition) +} + +func (i *Instance) SetReadinessFalse(msg string) { + condition := metav1.Condition{Type: readyConditionType, Status: metav1.ConditionFalse, Message: msg, Reason: resourceNotReadyReason} + meta.SetStatusCondition(&i.Status.Conditions, condition) +} + +// SetReadinessUnknown sets an unknown state for Status.Conditions.Ready +func (i *Instance) SetReadinessUnknown() { + condition := metav1.Condition{Type: readyConditionType, Status: metav1.ConditionUnknown, Reason: planInProgressReason} + meta.SetStatusCondition(&i.Status.Conditions, condition) +} + // wasRunAfter returns true if p1 was run after p2 func wasRunAfter(p1 PlanStatus, p2 PlanStatus) bool { if p1.Status == ExecutionNeverRun || p2.Status == ExecutionNeverRun || p1.LastUpdatedTimestamp == nil || p2.LastUpdatedTimestamp == nil { diff --git a/pkg/apis/kudo/v1beta1/zz_generated.deepcopy.go b/pkg/apis/kudo/v1beta1/zz_generated.deepcopy.go index da1c6a2e8..aa95b991a 100644 --- a/pkg/apis/kudo/v1beta1/zz_generated.deepcopy.go +++ b/pkg/apis/kudo/v1beta1/zz_generated.deepcopy.go @@ -19,7 +19,8 @@ limitations under the License. package v1beta1 import ( - v1 "k8s.io/api/core/v1" + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -135,6 +136,13 @@ func (in *InstanceStatus) DeepCopyInto(out *InstanceStatus) { (*out)[key] = *val.DeepCopy() } } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } @@ -379,7 +387,7 @@ func (in *OperatorVersionSpec) DeepCopyInto(out *OperatorVersionSpec) { } if in.UpgradableFrom != nil { in, out := &in.UpgradableFrom, &out.UpgradableFrom - *out = make([]v1.ObjectReference, len(*in)) + *out = make([]corev1.ObjectReference, len(*in)) copy(*out, *in) } return diff --git a/pkg/controller/instance/instance_controller.go b/pkg/controller/instance/instance_controller.go index f5bee8d7b..d27c1f595 100644 --- a/pkg/controller/instance/instance_controller.go +++ b/pkg/controller/instance/instance_controller.go @@ -50,6 +50,7 @@ import ( "github.com/kudobuilder/kudo/pkg/engine/renderer" "github.com/kudobuilder/kudo/pkg/engine/task" "github.com/kudobuilder/kudo/pkg/engine/workflow" + "github.com/kudobuilder/kudo/pkg/kubernetes/status" "github.com/kudobuilder/kudo/pkg/kudoctl/resources/dependencies" "github.com/kudobuilder/kudo/pkg/util/convert" ) @@ -157,6 +158,12 @@ func isForPipePod(e event.DeleteEvent) bool { // | Update instance with new | // | state of the execution | // +-------------------------------+ +// | +// v +// +-------------------------------+ +// | Update readiness even if | +// | no plan running | +// +-------------------------------+ // // Automatically generate RBAC rules to allow the Controller to read and write Deployments func (r *Reconciler) Reconcile(request ctrl.Request) (ctrl.Result, error) { @@ -187,8 +194,14 @@ func (r *Reconciler) Reconcile(request ctrl.Request) (ctrl.Result, error) { // get the scheduled plan plan, uid := scheduledPlan(instance, ov) if plan == "" { - log.Printf("InstanceController: Nothing to do, no plan scheduled for instance %s/%s", instance.Namespace, instance.Name) - return reconcile.Result{}, nil + // no plan is running, we still need to make sure the readiness property is up to date + err := setReadinessOnInstance(instance, r.Client) + if err != nil { + log.Printf("InstanceController: Error when computing readiness for %s/%s: %v", instance.Namespace, instance.Name, err) + return reconcile.Result{}, err + } + err = updateInstance(instance, oldInstance, r.Client) + return reconcile.Result{}, err } ensurePlanStatusInitialized(instance, ov) @@ -258,6 +271,20 @@ func (r *Reconciler) Reconcile(request ctrl.Request) (ctrl.Result, error) { return computeTheReconcileResult(instance, time.Now), nil } +func setReadinessOnInstance(instance *kudoapi.Instance, c client.Client) error { + ready, msg, err := status.IsReady(*instance, c) + log.Printf("Updatinginstance %s/%s readiness to: : %t", instance.Namespace, instance.Name, ready) + if err != nil { + return err + } + if ready { + instance.SetReadinessTrue(msg) + } else { + instance.SetReadinessFalse(msg) + } + return nil +} + // computeTheReconcileResult decides whether retry reconciliation or not // if plan was finished, reconciliation is not retried // for others it uses LastUpdatedTimestamp of a current plan @@ -536,5 +563,8 @@ func scheduledPlan(i *kudoapi.Instance, ov *kudoapi.OperatorVersion) (string, ty i.Spec.PlanExecution.Status = kudoapi.ExecutionNeverRun } + if i.Spec.PlanExecution.PlanName == kudoapi.DeployPlanName || i.Spec.PlanExecution.PlanName == kudoapi.UpgradePlanName || i.Spec.PlanExecution.PlanName == kudoapi.UpdatePlanName { + i.SetReadinessUnknown() + } return i.Spec.PlanExecution.PlanName, i.Spec.PlanExecution.UID } diff --git a/pkg/kubernetes/status/readiness.go b/pkg/kubernetes/status/readiness.go new file mode 100644 index 000000000..a65e9401a --- /dev/null +++ b/pkg/kubernetes/status/readiness.go @@ -0,0 +1,100 @@ +package status + +import ( + "context" + "fmt" + "log" + + kudoapi "github.com/kudobuilder/kudo/pkg/apis/kudo/v1beta1" + label "github.com/kudobuilder/kudo/pkg/util/kudo" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" +) + +// IsReady computes instance readiness based on current state of underlying resources +// currently readiness examines the following types: Pods, StatefulSets, Deployments, ReplicaSets and DaemonSets +// Instance is considered ready if all the resources linked to this instance are also ready (healthy) +func IsReady(i kudoapi.Instance, c client.Client) (ready bool, msg string, err error) { + resources, err := healthResources(c, i.Name, i.Namespace) + if err != nil { + return false, "", err + } + ready = true + readinessMessage := "" + for _, res := range resources { + healthy, _, err := IsHealthy(res) + if !healthy { + if readinessMessage == "" { + readinessMessage = fmt.Sprintf("%v", err) + } else { + readinessMessage += fmt.Sprintf(", %v", err) + } + ready = false + } + } + + return ready, readinessMessage, nil +} + +func healthResources(c client.Client, instanceName, instanceNamespace string) ([]runtime.Object, error) { + instanceLabels, err := labels.Parse(fmt.Sprintf("%s=%s,%s=%s", label.InstanceLabel, instanceName, label.HeritageLabel, "kudo")) + if err != nil { + return nil, fmt.Errorf("unable to create list of labels to define health: %v", err) + } + + dList := &appsv1.DeploymentList{} + err = c.List(context.TODO(), dList, &client.ListOptions{Namespace: instanceNamespace, LabelSelector: instanceLabels}) + if err != nil { + return nil, fmt.Errorf("unable to pull resources of type Deployment: %v", err) + } + + ssList := &appsv1.StatefulSetList{} + err = c.List(context.TODO(), ssList, &client.ListOptions{Namespace: instanceNamespace, LabelSelector: instanceLabels}) + if err != nil { + return nil, fmt.Errorf("unable to pull resources of type StatefulSet: %v", err) + } + + rsList := &appsv1.ReplicaSetList{} + err = c.List(context.TODO(), rsList, &client.ListOptions{Namespace: instanceNamespace, LabelSelector: instanceLabels}) + if err != nil { + return nil, fmt.Errorf("unable to pull resources of type ReplicaSet: %v", err) + } + + dsList := &appsv1.DaemonSetList{} + err = c.List(context.TODO(), dsList, &client.ListOptions{Namespace: instanceNamespace, LabelSelector: instanceLabels}) + if err != nil { + return nil, fmt.Errorf("unable to pull resources of type DaemonSet: %v", err) + } + + podsList := &corev1.PodList{} + err = c.List(context.TODO(), podsList, &client.ListOptions{Namespace: instanceNamespace, LabelSelector: instanceLabels}) + if err != nil { + return nil, fmt.Errorf("unable to pull resources of type Pod: %v", err) + } + + var result []runtime.Object + for i := range dList.Items { + result = append(result, &dList.Items[i]) + } + for i := range ssList.Items { + result = append(result, &ssList.Items[i]) + } + for i := range rsList.Items { + result = append(result, &rsList.Items[i]) + } + for i := range dsList.Items { + result = append(result, &dsList.Items[i]) + } + for i := range podsList.Items { + result = append(result, &podsList.Items[i]) + } + + log.Printf("Computing health out of %d Deployments, %d ReplicaSets, %d StatefulSets, %d DaemonSets, %d Pods", len(dList.Items), len(rsList.Items), len(ssList.Items), len(dsList.Items), len(podsList.Items)) + + return result, nil +} diff --git a/pkg/kubernetes/status/readiness_test.go b/pkg/kubernetes/status/readiness_test.go new file mode 100644 index 000000000..8424d3265 --- /dev/null +++ b/pkg/kubernetes/status/readiness_test.go @@ -0,0 +1,96 @@ +package status + +import ( + "context" + "testing" + + label "github.com/kudobuilder/kudo/pkg/util/kudo" + + kudoapi "github.com/kudobuilder/kudo/pkg/apis/kudo/v1beta1" + + apps "k8s.io/api/apps/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "k8s.io/apimachinery/pkg/runtime" + + "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/client/fake" +) + +func TestIsReady(t *testing.T) { + instance := &kudoapi.Instance{ + ObjectMeta: metav1.ObjectMeta{ + Name: "i", + Namespace: "n", + }, + } + tests := []struct { + name string + isReady bool + objs []runtime.Object + }{ + {"no linked resources, ready", true, []runtime.Object{}}, + {"one ready deployment", true, []runtime.Object{readyDeployment()}}, + {"one not ready deployment", false, []runtime.Object{notReadyDeployment()}}, + {"one ready and one not ready deployment", false, []runtime.Object{readyDeployment(), notReadyDeployment()}}, + } + for _, tt := range tests { + c := fake.NewFakeClientWithScheme(scheme.Scheme) + for _, obj := range tt.objs { + err := c.Create(context.TODO(), obj) + if err != nil { + t.Errorf("Error in test setup for %s. %v", tt.name, err) + } + } + ready, _, _ := IsReady(*instance, c) + if ready != tt.isReady { + t.Errorf("%s: expected instance to be ready: %t but got ready: %t", tt.name, tt.isReady, ready) + } + } +} + +func readyDeployment() runtime.Object { + var replicas int32 = 2 + return &apps.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "n", + Name: "foo", + UID: "8764ae47-9092-11e4-8393-42010af018ff", + Generation: 1, + Labels: map[string]string{label.HeritageLabel: "kudo", label.InstanceLabel: "i"}, + }, + Spec: apps.DeploymentSpec{ + Replicas: &replicas, + }, + Status: apps.DeploymentStatus{ + ObservedGeneration: 1, + Replicas: 2, + UpdatedReplicas: 2, + AvailableReplicas: 2, + UnavailableReplicas: 0, + }, + } +} + +func notReadyDeployment() runtime.Object { + var replicas int32 = 2 + return &apps.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "n", + Name: "foo2", + UID: "8764ae47-9092-11e4-8393-42010af018ff", + Generation: 1, + Labels: map[string]string{label.HeritageLabel: "kudo", label.InstanceLabel: "i"}, + }, + Spec: apps.DeploymentSpec{ + Replicas: &replicas, + }, + Status: apps.DeploymentStatus{ + ObservedGeneration: 1, + Replicas: 2, + UpdatedReplicas: 2, + AvailableReplicas: 1, + UnavailableReplicas: 1, + }, + } +} diff --git a/pkg/kudoctl/cmd/testdata/deploy-kudo-ns.yaml.golden b/pkg/kudoctl/cmd/testdata/deploy-kudo-ns.yaml.golden index b4de0be48..2f6d4c047 100644 --- a/pkg/kudoctl/cmd/testdata/deploy-kudo-ns.yaml.golden +++ b/pkg/kudoctl/cmd/testdata/deploy-kudo-ns.yaml.golden @@ -385,6 +385,49 @@ spec: status: description: InstanceStatus defines the observed state of Instance properties: + conditions: + items: + description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array planStatus: additionalProperties: description: "PlanStatus is representing status of a plan \n These are valid states and transitions \n | Never executed | | v | Error |<------>| Pending | ^ | | v | +-------+--------+ | +-------+--------+ | | v v | Fatal error | | Complete |" diff --git a/pkg/kudoctl/cmd/testdata/deploy-kudo-sa.yaml.golden b/pkg/kudoctl/cmd/testdata/deploy-kudo-sa.yaml.golden index adff89b74..16fb4d6b9 100644 --- a/pkg/kudoctl/cmd/testdata/deploy-kudo-sa.yaml.golden +++ b/pkg/kudoctl/cmd/testdata/deploy-kudo-sa.yaml.golden @@ -385,6 +385,49 @@ spec: status: description: InstanceStatus defines the observed state of Instance properties: + conditions: + items: + description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array planStatus: additionalProperties: description: "PlanStatus is representing status of a plan \n These are valid states and transitions \n | Never executed | | v | Error |<------>| Pending | ^ | | v | +-------+--------+ | +-------+--------+ | | v v | Fatal error | | Complete |" diff --git a/pkg/kudoctl/cmd/testdata/deploy-kudo.json.golden b/pkg/kudoctl/cmd/testdata/deploy-kudo.json.golden index 062198ab6..945674242 100644 --- a/pkg/kudoctl/cmd/testdata/deploy-kudo.json.golden +++ b/pkg/kudoctl/cmd/testdata/deploy-kudo.json.golden @@ -533,6 +533,60 @@ "description": "InstanceStatus defines the observed state of Instance", "type": "object", "properties": { + "conditions": { + "type": "array", + "items": { + "description": "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }", + "type": "object", + "required": [ + "lastTransitionTime", + "message", + "reason", + "status", + "type" + ], + "properties": { + "lastTransitionTime": { + "description": "lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.", + "type": "string", + "format": "date-time" + }, + "message": { + "description": "message is a human readable message indicating details about the transition. This may be an empty string.", + "type": "string", + "maxLength": 32768 + }, + "observedGeneration": { + "description": "observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance.", + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "reason": { + "description": "reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.", + "type": "string", + "maxLength": 1024, + "minLength": 1, + "pattern": "^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$" + }, + "status": { + "description": "status of the condition, one of True, False, Unknown.", + "type": "string", + "enum": [ + "True", + "False", + "Unknown" + ] + }, + "type": { + "description": "type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)", + "type": "string", + "maxLength": 316, + "pattern": "^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$" + } + } + } + }, "planStatus": { "description": "slice would be enough here but we cannot use slice because order of sequence in yaml is considered significant while here it's not", "type": "object", diff --git a/pkg/kudoctl/cmd/testdata/deploy-kudo.yaml.golden b/pkg/kudoctl/cmd/testdata/deploy-kudo.yaml.golden index 0cde0942d..33bf9809f 100644 --- a/pkg/kudoctl/cmd/testdata/deploy-kudo.yaml.golden +++ b/pkg/kudoctl/cmd/testdata/deploy-kudo.yaml.golden @@ -385,6 +385,49 @@ spec: status: description: InstanceStatus defines the observed state of Instance properties: + conditions: + items: + description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array planStatus: additionalProperties: description: "PlanStatus is representing status of a plan \n These are valid states and transitions \n | Never executed | | v | Error |<------>| Pending | ^ | | v | +-------+--------+ | +-------+--------+ | | v v | Fatal error | | Complete |" diff --git a/pkg/kudoctl/kudoinit/crd/bindata.go b/pkg/kudoctl/kudoinit/crd/bindata.go index 250831ccd..1e8f45d78 100644 --- a/pkg/kudoctl/kudoinit/crd/bindata.go +++ b/pkg/kudoctl/kudoinit/crd/bindata.go @@ -80,7 +80,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _configCrdsKudoDev_instancesYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xe4\x59\xdd\x6f\x1b\xb9\x11\x7f\xd7\x5f\x31\xf0\x3d\x38\xc6\x59\xab\x4b\xda\x87\x42\x28\x0a\xa4\x4e\xae\x50\x7b\xb5\x8d\xc8\x4e\x71\xc8\xa5\x00\x45\x8e\xb4\xac\xb9\xe4\x86\x1f\x92\xd5\xcb\xfd\xef\xc5\x0c\x77\x57\x1f\xd6\x97\xd3\xcb\xf5\xa1\x7c\xb1\xc5\x1d\xce\xc7\x6f\x86\xf3\xb1\xdb\xeb\xf7\xfb\x3d\x51\xeb\xf7\xe8\x83\x76\x76\x08\xa2\xd6\xf8\x18\xd1\xd2\xaf\x50\x3c\xfc\x21\x14\xda\x0d\xe6\x2f\x27\x18\xc5\xcb\xde\x83\xb6\x6a\x08\x57\x29\x44\x57\xbd\xc3\xe0\x92\x97\xf8\x06\xa7\xda\xea\xa8\x9d\xed\x55\x18\x85\x12\x51\x0c\x7b\x00\xc2\x5a\x17\x05\x6d\x07\xfa\x09\x20\x9d\x8d\xde\x19\x83\xbe\x3f\x43\x5b\x3c\xa4\x09\x4e\x92\x36\x0a\x3d\x4b\x68\xe5\xcf\xbf\x2b\x7e\x5f\x7c\xd7\x03\x90\x1e\xf9\xf8\x9d\xae\x30\x44\x51\xd5\x43\xb0\xc9\x98\x1e\x80\x15\x15\x0e\x41\xdb\x10\x85\x95\x18\x8a\x87\xa4\x5c\xa1\x70\xde\x0b\x35\x4a\x12\x36\xf3\x2e\xd5\x43\xe8\xf6\xf3\x91\x46\x8f\x6c\xc3\xa8\x39\xcd\x5b\x46\x87\xf8\xb7\x8d\xed\x1f\x74\x88\xfc\xa8\x36\xc9\x0b\xb3\x26\x8d\x77\x83\xb6\xb3\x64\x84\x5f\xed\xf7\x00\x82\x74\x35\x0e\xe1\x9a\x44\xd5\x42\xa2\xa2\xbd\x34\xf1\x0d\x4e\x8d\xf8\x10\x45\x4c\x61\x08\x3f\xff\xd2\x03\x98\x0b\xa3\x15\x5b\x99\x1f\xba\x1a\xed\xeb\xdb\xd1\xfb\xdf\x8d\x65\x89\x95\xc8\x9b\x00\x0a\x83\xf4\xba\x66\xba\x4e\x45\xd0\x01\x62\x89\x90\x49\x61\xea\x3c\xff\xec\x14\x85\xd7\xb7\xa3\xa2\x61\x50\x7b\x57\xa3\x8f\xba\x55\x82\xd6\x9a\xd3\xbb\xbd\x2d\x51\xe7\xa4\x4b\xa6\x01\x45\x6e\xc6\x2c\xb2\x71\x16\x2a\x08\x59\xb8\x9b\x42\x2c\x75\x00\x8f\xb5\xc7\x80\x36\x3b\x9e\xb6\x85\x05\x37\xf9\x17\xca\x58\xc0\x18\x3d\x1d\x84\x50\xba\x64\x14\xc5\xc3\x1c\x7d\x04\x8f\xd2\xcd\xac\xfe\x77\xc7\x2d\x40\x74\x2c\xc6\x88\x88\x21\x82\xb6\x11\xbd\x15\x86\xd0\x4a\x78\x09\xc2\x2a\xa8\xc4\x12\x3c\x12\x5f\x48\x76\x8d\x03\x93\x84\x02\xfe\xee\x3c\x41\x31\x75\x43\x28\x63\xac\xc3\x70\x30\x98\xe9\xd8\x86\xb3\x74\x55\x95\xac\x8e\xcb\x01\x07\xa5\x9e\xa4\xe8\x7c\x18\x28\x9c\xa3\x19\x04\x3d\xeb\x0b\x2f\x4b\x1d\x51\xc6\xe4\x71\x20\x6a\xdd\x67\x65\x2d\x47\x73\x51\xa9\x6f\x3a\x9f\x9e\xaf\x41\x17\x97\xe4\xfe\x10\xbd\xb6\xb3\x6e\x9b\xa3\x6d\x2f\xbe\x14\x74\xe4\x47\xd1\x1c\xcb\xfa\xaf\x60\xa4\x2d\x42\xe2\xdd\xdb\xf1\x1d\xb4\x42\x33\xd4\x19\xd5\x15\x69\x58\x01\x4c\xe0\x68\x3b\x45\x9f\x29\xa7\xde\x55\xcc\x05\xad\xaa\x9d\xb6\x91\x7f\x48\xa3\xd1\x46\x0a\xd0\x4a\x47\xf2\xdc\xa7\x84\x21\x12\xf6\x05\x5c\xf1\xe5\x85\x09\x42\xaa\x95\x88\xa8\x0a\x18\x59\xb8\x12\x15\x9a\x2b\x11\xf0\xab\xc3\x4b\x48\x86\x3e\x41\x77\x1c\xe0\xf5\x9c\xb3\x49\x98\x11\xea\xb6\xdb\xe4\xb0\xd3\x13\xed\xa5\x1a\xd7\x28\x37\x42\x5d\x61\xd0\x9e\x42\x33\x8a\x88\x14\xd0\x2d\x65\xb1\xc6\x6a\xd7\xf5\x6a\xae\xb3\x17\xd1\xf9\x1d\xf7\xec\x89\x06\x37\x9b\xb4\xac\xae\x9e\x6a\xa4\xe0\xf0\x38\x45\x8f\x74\xe7\xa3\xa3\x58\xc9\x8f\xe4\x93\x33\xcd\x4d\xdb\x12\xb3\x4f\xbb\xfd\x49\x60\xa7\x82\xaf\x6f\x47\xed\xc5\xcf\xf7\x1d\x5b\xbd\x9e\x48\xdc\xeb\xac\x76\x4d\x35\x1a\x75\x2b\x62\x79\x54\xea\xf9\x68\x9a\xc5\xf0\xf5\x60\xf3\x6b\x8d\x12\x37\x72\x0b\x27\x3d\x14\xaa\xd9\xa4\x48\xf2\xd8\x3c\xbb\xcc\x97\xa0\xb9\x5f\xab\xdc\x13\x85\xb6\x20\x72\x06\x86\xbf\x8e\x6f\xae\x07\x7f\x71\x59\x2f\x10\x52\x62\x08\xd9\xe5\x15\xda\x78\x09\x21\xc9\x12\x44\x68\xa3\x61\x4c\x4f\x8a\x4a\x58\x3d\xc5\x10\x8b\x86\x1b\xfa\xf0\xe1\xd5\xc7\x02\xbe\x77\x1e\xf0\x51\x54\xb5\xc1\x4b\xd0\x19\xa9\xee\xb6\xb6\x8e\xd4\x21\x1b\xd3\x9d\x85\x85\x8e\x25\xab\x54\x3b\xd5\x28\xbd\x60\x65\xa3\x78\x40\x70\x8d\xb2\x09\xc1\xe8\x07\x1c\xc2\x19\x45\xc1\x9a\xe8\x9f\xa9\xc4\xfd\x72\x06\x2f\x16\x25\x7a\x84\x33\xfa\x79\x96\x05\x76\x09\x95\xf6\x5a\xdf\xad\x04\xc7\x52\x44\x88\x5e\xcf\x66\x48\x91\xce\x99\x82\x6e\xe3\x05\x38\x4f\xfa\x5b\xb7\x46\xcc\x2c\x08\xcf\x26\x3c\xd5\x13\x45\x3e\xbc\xfa\x78\x06\x2f\x36\xed\x02\x6d\x15\x3e\xc2\x2b\xd0\x36\x5b\x56\x3b\x75\x51\xc0\x1d\x7b\x66\x69\xa3\x78\x24\x9e\xb2\x74\x01\x2d\x38\x6b\x96\xa4\x71\x29\xe6\x08\xc1\x55\x08\x0b\x34\xa6\x9f\x6f\xa5\x82\x85\x58\x92\x0d\x2d\x94\xe4\x55\x01\xb5\xf0\x71\xab\xdc\xdc\xdd\xbc\xb9\x19\x66\x69\xe4\xb6\x99\x25\x11\x94\xd6\xa6\x9a\x8a\x09\x55\x91\x9c\x1e\xd9\xe7\xa4\x48\xca\x4e\x8a\x0e\x64\x29\xec\x0c\xb3\xb6\x08\xd3\x44\x89\xaa\x38\x7f\x6e\x94\x6f\xe7\xfe\xdd\x01\xce\x35\x60\xfb\x42\xfd\x8f\x32\xec\x49\x66\x71\xfb\x75\xd4\xac\xeb\xb5\x58\x3b\x68\x16\x35\x82\xde\x62\x44\xb6\x4c\x39\x19\xc8\x28\x89\x75\x0c\x03\x37\x47\x3f\xd7\xb8\x18\x2c\x9c\x7f\xd0\x76\xd6\xa7\x60\xea\x67\x0f\x87\x01\x37\x75\x83\x6f\xf8\xcf\x17\x59\xc1\x6d\xda\x69\xa6\x30\xe9\x6f\x61\x0f\xc9\x09\x83\x67\x9b\xd3\x36\x07\xa7\x66\xf3\xf3\x71\x5b\x44\xb6\x4e\x52\xf8\x2f\x4a\x2d\xcb\xb6\xa3\x5b\xcb\x58\x95\x50\x39\xa5\x09\xbb\xfc\xea\x21\x4a\xa0\x25\x4f\xb2\x97\xfd\x66\x76\xe8\x0b\xab\xe8\xff\xa0\x43\xa4\xfd\x67\xa3\x94\xf4\x09\x17\xf2\x7e\xf4\xe6\xb7\x09\xdc\xa4\x9f\x7d\xfb\x76\x76\x36\xb4\x6a\xe1\x45\x85\x11\xfd\x93\x22\x2f\x94\xe2\xe9\x4c\x98\xdb\x03\x8d\xc0\x17\xc9\x34\xc2\xbe\x7d\x44\x99\xe2\xb1\xe6\xe6\xfc\x8e\x8b\x92\xf0\x08\x71\xe1\x28\x85\x53\x5b\x43\xe7\x01\x5b\x06\x20\x85\xa5\x96\xb3\xab\x44\x43\x80\x97\x17\x54\x39\xb4\x47\x19\xa9\x26\x94\xde\xa5\x59\xd9\x34\xa5\x9c\xee\x41\x3a\xef\x31\xd4\xce\x2a\x2a\x04\x1d\x0a\x6d\xea\x5e\xef\xeb\x8a\xdb\x0e\x23\xa8\x44\x0d\xf0\xea\x02\x9e\xf0\x0e\x18\xb9\xeb\x6e\x02\x60\xf3\xfc\xba\xbd\xfc\x8b\x93\x5c\x2e\x20\xff\x28\xb5\xc1\x4e\x5b\x78\xf1\xf2\xa2\xb5\x24\x40\x29\xea\x1a\x6d\xa0\xb2\xea\x97\x10\x75\x85\x20\x20\x05\xf4\x4d\xa1\x09\xb9\x82\x65\xe5\x2e\x41\xac\xd4\x7a\xf1\xea\x62\xad\x34\x33\x60\x7c\x29\x03\xb5\xfa\xaa\x1b\xfa\x82\x8e\x29\xcf\xda\xb0\x28\xd1\xae\x45\x03\x28\x87\xc1\x9e\x9f\xc7\xb6\xa6\x61\x31\x2b\x48\x1c\x7a\xed\x94\x96\x30\x11\xf2\x21\xd5\xdc\x8f\x74\x72\x28\x7a\xbd\x56\xed\xf4\x81\x8f\x3a\x30\x28\x0d\xed\x54\x1b\x2c\xe0\x75\x17\x57\x66\xd9\xf4\x2b\x8e\xad\xf4\xce\x55\xac\x99\x24\xe4\x0c\x17\x68\xbb\xc1\x34\xdf\x6b\xb2\xcf\x27\x6b\xd9\x71\x46\xd8\xb0\x55\x6f\xe1\xda\x45\x1c\xc2\x06\xea\x0d\xd8\x6d\x87\xce\x80\x70\x4b\x42\x12\xf6\xc4\x42\xc8\x1d\xce\x68\x0c\x57\xf7\xef\xde\xbd\xbd\xbe\xfb\xe1\xc7\x26\xea\x68\xb0\xb9\xe1\xb6\x7a\x6d\x70\x5e\x7b\x51\x01\x2f\x46\x57\x17\x04\x8d\x72\x16\x73\x23\x93\xf1\x68\xb4\xb9\x5c\xef\x20\x16\xda\x18\x8a\x5f\x69\x50\x78\xe2\xfc\x56\xc8\x72\x3b\xc6\x4b\x41\xbe\x4e\x56\x7f\x4a\x08\x94\x68\x82\x6b\x7b\x52\xf6\x23\x99\xc2\x47\x26\x94\x7c\xfa\x2b\x97\xe8\x98\x05\x70\x53\x24\xc0\xe2\x82\x8e\x6f\x67\x8f\x43\xad\x7e\xdd\xc4\xeb\xae\x04\x78\x30\x69\x36\x6f\x2c\x8e\xe5\xcd\xce\x47\x63\xa6\x07\x29\x6a\x72\x63\x1e\xa3\xba\xf1\x89\xb3\xaa\x33\xc6\xa5\xe7\x4f\x0d\xa7\x64\x6f\xc2\x94\x07\x6a\xe2\x94\x1d\x5f\x3a\xa3\x42\x8b\xf9\xe8\x4d\xf3\x8e\xe0\x12\xb4\x95\x26\x71\xa8\xdc\xdf\x8f\xde\x84\x02\xe0\xcf\x28\x45\x0a\xd4\x6f\x92\xc7\xcf\x23\xdc\x5c\xff\xf0\x23\x5d\xd4\x4c\xd1\xb8\x9b\xd8\x5b\x10\x46\xe7\x37\x15\x59\x59\x3e\x9d\x7b\x51\x96\xdc\x59\xaf\x6d\xa4\x39\x9b\xe2\xb3\x44\x53\x53\xea\x79\x40\x08\xc9\x37\xda\x11\x63\x7e\xca\x45\x01\x94\xe3\x1e\x75\x86\x91\xe2\x70\x6a\x78\xfa\xfe\x55\x6a\xc4\xee\xa1\xf8\x89\x6f\x77\x8f\xc5\xd9\xa5\xeb\x83\xb1\x9b\x34\x39\xe8\xc9\x64\x7c\xc2\x60\x4c\xb1\x38\xde\x19\x56\xa7\x55\xab\x0d\x25\xcf\x6e\x3b\x6e\xb0\xfe\x0e\x8a\xe7\xbd\xbc\xcd\xa5\x82\xef\xd5\x4f\x16\xee\x4a\x0c\xb9\x16\xe5\xe1\x8f\x0d\xc8\x3e\x88\x5e\xd8\xa0\x73\x22\xfd\xc9\x3e\x45\x9d\xd7\x67\xb8\xa6\x44\xde\xe5\x10\xf8\xbc\x87\x70\x75\xe0\xf0\x9a\x67\x8a\xb7\xde\x3b\xcf\xf4\x7f\xec\xf3\xfa\x13\x6f\xdf\x62\xce\x67\xeb\x9c\xfe\x79\x44\xd2\x3e\x89\xf3\x3d\xcf\xbf\xcd\x02\xfb\xed\xdf\xfe\xb7\xff\x2d\xe1\xb6\x46\xf3\xbd\x1a\x7d\x86\xef\x45\x14\x06\x90\xcd\xff\xbc\x71\xf0\xca\xd1\x14\x1d\x91\x37\xce\x9e\xa6\xb4\x03\x21\x02\x60\x44\x88\xf7\xf9\xfd\xd5\xea\x1d\xf2\x0e\x3a\xa0\x62\x55\x89\x38\x04\xa2\xed\x53\x79\xde\x49\x65\x93\x31\x62\x62\x70\x08\xd1\xa7\xdd\x24\x07\xd3\x17\x40\x85\x21\x88\xd9\xce\x0c\x7c\xf4\xec\xbe\xa9\xeb\xe8\xc1\xba\x14\x61\x37\x40\x00\x3a\x62\xb5\xe7\xd1\xd6\x25\xbb\x25\x2e\xa7\x5c\x32\xa2\xdb\xc3\xf0\xb0\xbb\xf2\x3a\x08\xd1\x49\xf6\xe6\xb5\x1f\xae\x67\x30\xd9\x5f\xf9\xda\xf5\xeb\x57\xc0\x67\x2a\x88\xf5\x41\xfd\x0e\x3a\x78\x87\x09\xe3\x88\xf5\x09\x5e\x26\xb9\x07\x99\x9e\xe2\xea\xbc\x4e\x70\x78\x5e\x27\x01\x92\xd7\x31\xe7\x3f\x9b\xe1\xf1\x40\xc8\xeb\xeb\x85\xc3\x33\x55\xde\x3b\xb3\xed\x22\x13\xde\x8b\xe5\x1e\xaa\xa3\x8c\x0e\xb3\x38\x04\xdc\xd7\x00\xeb\x08\x40\x7b\x3a\xc8\xff\xd3\x1e\xf2\x08\x5c\x07\x5c\xbf\x01\x57\x30\x5a\x62\xf3\xae\x7a\x82\x80\x96\x07\x69\x1e\xf8\x27\x29\x12\x10\x32\x7f\x4f\x22\x10\x32\xf1\xa4\x01\xc9\x79\x85\x9e\x1c\x1b\xf0\x53\xca\x6f\x99\x2c\x2c\x45\x65\xf8\x75\xb0\xb3\x41\x2b\x9e\x7e\x82\x9e\x59\x3d\xd5\x52\xd8\x08\x0b\x1e\xb4\x99\xbd\x8e\xe7\xfc\x4a\xf7\x8b\x1b\xe0\xad\xad\xd5\x47\xe8\xe6\x7b\x77\xb7\xc5\x21\xdc\x6f\xbe\x3c\xaf\x9e\x02\xe4\x26\x78\xad\x25\x08\xd1\x79\xca\x67\x79\x67\x15\xff\x42\x4a\xac\x23\xaa\xeb\xed\x2f\xd1\x67\x67\x1b\x1f\x9a\xf9\xa7\xa4\x19\x36\x7f\x3b\x87\x0f\x1f\x7b\x99\x2b\xaa\xf7\xad\x32\xb4\xf9\x9f\x00\x00\x00\xff\xff\xfe\x85\x1d\x70\xba\x1f\x00\x00") +var _configCrdsKudoDev_instancesYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xe4\x1a\x69\x73\xdb\xc6\xf5\xbb\x7e\xc5\x1b\xa6\x33\x92\x1c\x12\xb4\x94\x4c\x9a\x70\xea\x7a\x5c\xd9\xce\xa8\xf1\xa1\xb1\xe4\x74\x52\x49\x69\x96\xc0\x23\xb1\x11\xb0\x0b\xef\x2e\x44\x31\x71\xfe\x7b\xe7\xbd\x5d\x1c\x24\xc1\x43\x8a\x93\x7e\x28\xbe\x48\xdc\xe3\xdd\x37\xb0\x37\x18\x0c\xf6\x44\x21\xbf\x47\x63\xa5\x56\x23\x10\x85\xc4\x3b\x87\x8a\x7e\xd9\xe8\xe6\x6b\x1b\x49\x3d\xbc\x3d\x1a\xa3\x13\x47\x7b\x37\x52\x25\x23\x38\x29\xad\xd3\xf9\x3b\xb4\xba\x34\x31\x3e\xc7\x89\x54\xd2\x49\xad\xf6\x72\x74\x22\x11\x4e\x8c\xf6\x00\x84\x52\xda\x09\x5a\xb6\xf4\x13\x20\xd6\xca\x19\x9d\x65\x68\x06\x53\x54\xd1\x4d\x39\xc6\x71\x29\xb3\x04\x0d\x63\xa8\xf0\xdf\x3e\x8e\xbe\x8c\x1e\xef\x01\xc4\x06\xf9\xfa\x85\xcc\xd1\x3a\x91\x17\x23\x50\x65\x96\xed\x01\x28\x91\xe3\x08\xa4\xb2\x4e\xa8\x18\x6d\x74\x53\x26\x3a\x4a\xf0\x76\xcf\x16\x18\x13\xb2\xa9\xd1\x65\x31\x82\x7a\xdd\x5f\x09\x74\x78\x1e\x4e\xc3\x6d\x5e\xca\xa4\x75\xdf\x2d\x2c\xbf\x92\xd6\xf1\x56\x91\x95\x46\x64\x2d\x6c\xbc\x6a\xa5\x9a\x96\x99\x30\xcd\xfa\x1e\x80\x8d\x75\x81\x23\x78\x43\xa8\x0a\x11\x63\x42\x6b\xe5\xd8\x04\x39\x05\xf4\xd6\x09\x57\xda\x11\xfc\xfa\xdb\x1e\xc0\xad\xc8\x64\xc2\x5c\xfa\x4d\x5d\xa0\x7a\x76\x76\xfa\xfd\x17\xe7\x71\x8a\xb9\xf0\x8b\x00\x09\xda\xd8\xc8\x82\xcf\xd5\x24\x82\xb4\xe0\x52\x04\x7f\x14\x26\xda\xf0\xcf\x9a\x50\x78\x76\x76\x1a\x05\x00\x85\xd1\x05\x1a\x27\x2b\x22\xe8\x69\x29\xbd\x5e\x5b\x42\xb5\x4f\xb4\xf8\x33\x90\x90\x9a\xd1\xa3\x0c\xca\xc2\x04\xac\x47\xae\x27\xe0\x52\x69\xc1\x60\x61\xd0\xa2\xf2\x8a\xa7\x65\xa1\x40\x8f\x7f\xc6\xd8\x45\x70\x8e\x86\x2e\x82\x4d\x75\x99\x25\x64\x0f\xb7\x68\x1c\x18\x8c\xf5\x54\xc9\x5f\x6a\x68\x16\x9c\x66\x34\x99\x70\x68\x1d\x48\xe5\xd0\x28\x91\x91\xb4\x4a\xec\x83\x50\x09\xe4\x62\x0e\x06\x09\x2e\x94\xaa\x05\x81\x8f\xd8\x08\x5e\x6b\x43\xa2\x98\xe8\x11\xa4\xce\x15\x76\x34\x1c\x4e\xa5\xab\xcc\x39\xd6\x79\x5e\x2a\xe9\xe6\x43\x36\x4a\x39\x2e\x9d\x36\x76\x98\xe0\x2d\x66\x43\x2b\xa7\x03\x61\xe2\x54\x3a\x8c\x5d\x69\x70\x28\x0a\x39\x60\x62\x15\x5b\x73\x94\x27\x9f\xd5\x3a\xdd\x6f\x89\xce\xcd\x49\xfd\xd6\x19\xa9\xa6\xf5\x32\x5b\xdb\x5a\xf9\x92\xd1\x91\x1e\x45\xb8\xe6\xe9\x6f\xc4\x48\x4b\x24\x89\x77\x2f\xce\x2f\xa0\x42\xea\x45\xed\xa5\xda\x1c\xb5\x8d\x80\x49\x38\x52\x4d\xd0\xf8\x93\x13\xa3\x73\x86\x82\x2a\x29\xb4\x54\x8e\x7f\xc4\x99\x44\xe5\xc8\x40\x73\xe9\x48\x73\x1f\x4a\xb4\x8e\x64\x1f\xc1\x09\x3b\x2f\x8c\x11\xca\x22\x11\x0e\x93\x08\x4e\x15\x9c\x88\x1c\xb3\x13\x61\xf1\x0f\x17\x2f\x49\xd2\x0e\x48\x74\xdb\x05\xdc\x8e\x39\x8b\x07\xbd\x84\xea\xe5\x2a\x38\x74\x6a\xa2\x72\xaa\xf3\x02\xe3\x05\x53\x4f\xd0\x4a\x43\xa6\xe9\x84\x43\x32\xe8\xea\x64\xd4\x02\xd5\xe5\x5e\xc1\x9d\x8d\x70\xda\x74\xf8\xd9\x0a\x05\x6f\x17\xcf\x32\xb9\x72\x22\x91\x8c\xc3\xe0\x04\x0d\x92\xcf\x3b\x4d\xb6\xe2\xb7\xe2\x95\x3b\xc1\xd3\x96\xd0\xac\xa3\x6e\x7d\x10\xe8\x24\xf0\xd9\xd9\x69\xe5\xf8\xde\xdf\xb1\xa2\x6b\x05\xe3\x5a\x65\x55\xcf\x44\x62\x96\x9c\x09\x97\x6e\xc5\xba\x7f\x3a\xf1\x68\xd8\x3d\x98\xfd\x42\x62\x8c\x0b\xb1\x85\x83\x1e\x8a\x24\x2c\x92\x25\x19\x0c\x7b\x7d\xef\x04\xc1\xbf\x9a\xd8\xe3\x84\x54\x20\x7c\x04\x86\x7f\x9e\xbf\x7d\x33\xfc\x56\x7b\xba\x40\xc4\x31\x5a\xeb\x55\x9e\xa3\x72\x7d\xb0\x65\x9c\x82\xb0\x95\x35\x9c\xd3\x4e\x94\x0b\x25\x27\x68\x5d\x14\xa0\xa1\xb1\x97\xc7\xd7\x11\xbc\xd4\x06\xf0\x4e\xe4\x45\x86\x7d\x90\x5e\x52\xb5\xb7\x56\x8a\x94\xd6\x33\x53\xdf\x85\x99\x74\x29\x93\x54\xe8\x24\x10\x3d\x63\x62\x9d\xb8\x41\xd0\x81\xd8\x12\x21\x93\x37\x38\x82\x1e\x59\x41\x0b\xf5\xaf\x94\xe2\x7e\xeb\xc1\xc1\x2c\x45\x83\xd0\xa3\x9f\x3d\x8f\xb0\x0e\xa8\xb4\x56\xe9\xae\x41\xec\x52\xe1\xc0\x19\x39\x9d\x22\x59\x3a\x47\x0a\xf2\xc6\x43\xd0\x86\xe8\x57\xba\x75\x98\x41\x90\x3c\x83\x79\x26\x2b\x84\x5c\x1e\x5f\xf7\xe0\x60\x91\x2f\x90\x2a\xc1\x3b\x38\x06\xa9\x3c\x67\x85\x4e\x0e\x23\xb8\x60\xcd\xcc\x95\x13\x77\x04\x33\x4e\xb5\x45\x05\x5a\x65\x73\xa2\x38\x15\xb7\x08\x56\xe7\x08\x33\xcc\xb2\x81\xf7\xca\x04\x66\x62\x4e\x3c\x54\xa2\x24\xad\x0a\x28\x84\x71\x4b\xe9\xe6\xe2\xed\xf3\xb7\x23\x8f\x8d\xd4\x36\x55\x84\x82\xc2\xda\x44\x52\x32\xa1\x2c\xe2\xc3\x23\xeb\x9c\x08\x29\xbd\x92\x9c\x86\x38\x15\x6a\x8a\x9e\x5a\x84\x49\x49\x81\x2a\xda\xbf\xaf\x95\x2f\xc7\xfe\x6e\x03\xe7\x1c\xb0\xec\x50\xff\xa3\x08\xbb\x13\x5b\x5c\x7e\x6d\x65\xeb\x4d\xcb\xd6\x36\xb2\x45\x85\xa0\x51\xe8\x90\x39\x4b\x74\x6c\x89\xa9\x18\x0b\x67\x87\xfa\x16\xcd\xad\xc4\xd9\x70\xa6\xcd\x8d\x54\xd3\x01\x19\xd3\xc0\x6b\xd8\x0e\xb9\xa8\x1b\x7e\xc6\x7f\x1e\xc4\x05\x97\x69\xbb\xb1\xc2\x47\xff\x0c\x7e\x08\x8f\x1d\xde\x9b\x9d\xaa\x38\xd8\x35\x9a\xef\x9f\x57\x49\x64\xe9\x26\x99\xff\x2c\x95\x71\x5a\x55\x74\xad\x88\x95\x8b\xc4\x87\x34\xa1\xe6\x7f\xb8\x89\x92\xd0\x4a\x43\xb8\xe7\x83\xd0\x3b\x0c\x84\x4a\xe8\x7f\x2b\xad\xa3\xf5\x7b\x4b\xa9\x94\x3b\x38\xe4\xfb\xd3\xe7\x7f\x8e\xe1\x96\xf2\xde\xde\xd7\x59\xd9\xd0\x53\x08\x23\x72\x74\x68\x56\x92\xbc\x48\x12\xee\xce\x44\x76\xb6\xa1\x10\x78\x10\xce\x4c\xa8\x17\x77\x18\x97\x6e\x5b\x71\xb3\x7f\xc1\x49\x49\x18\x04\x37\xd3\x14\xc2\xa9\xac\xa1\xfb\x80\x15\x00\x88\x85\xa2\x92\xb3\xce\x44\x23\x80\xa3\x43\xca\x1c\xd2\x60\xec\x28\x27\xa4\x46\x97\xd3\x34\x14\xa5\x1c\xee\x21\xd6\xc6\xa0\x2d\xb4\x4a\x28\x11\xd4\x52\xa8\x42\x77\xbb\xae\x8b\xce\x6a\x19\x41\x2e\x0a\x80\xe3\x43\x58\x81\x6d\xd1\x71\xd5\x1d\x0c\x60\xf1\x7e\x9b\x5f\xfe\xc5\x41\xce\x27\x90\x7f\xa5\x32\xc3\x9a\x5a\x38\x38\x3a\xac\x38\xb1\x90\x8a\xa2\x40\x65\x29\xad\x9a\x39\x38\x99\x23\x08\x28\x2d\x9a\x90\x68\xac\xcf\x60\x9e\xb8\x3e\x88\x86\xac\x83\xe3\xc3\x56\x6a\x66\x81\xb1\x53\x5a\x2a\xf5\x93\xba\xe9\xb3\xd2\x95\xbe\xd7\x86\x59\x8a\xaa\x65\x0d\x90\x68\xb4\x6a\x7f\xdf\x55\x39\x0d\xa3\x69\x44\xe8\xd0\x48\x9d\xc8\x18\xc6\x22\xbe\x29\x0b\xae\x47\x6a\x3c\x64\xbd\x46\x26\x55\xf7\x81\x77\xd2\xb2\x50\xc2\xd9\x89\xcc\x30\x82\x67\xb5\x5d\x65\xf3\x50\xaf\x68\xe6\xd2\x68\x9d\x33\x65\x31\x49\x2e\xe3\x04\xad\x16\x80\x7a\xbf\x26\xfe\x4c\xa9\x14\x2b\x2e\x13\xca\x2e\xe5\x5b\x78\xa3\x1d\x8e\x60\x41\xea\x41\xd8\x55\x85\xce\x02\xe1\x92\x84\x30\xac\xb1\x05\xeb\x2b\x9c\xd3\x73\x38\x79\xff\xee\xdd\x8b\x37\x17\xaf\x7e\x08\x56\x47\x8d\xcd\x5b\x2e\xab\x5b\x8d\x73\x6b\x50\x01\x07\xa7\x27\x87\x24\x9a\x44\x2b\xf4\x85\x8c\x97\x47\xa0\xa6\xdf\xae\x20\x66\x32\xcb\xc8\x7e\xe3\x0c\x85\x21\xc8\x2f\x44\x9c\x2e\xdb\x78\x2a\x48\xd7\xa5\x92\x1f\x4a\x04\x0a\x34\x56\x57\x35\x29\xeb\x91\x58\xe1\x2b\x63\x0a\x3e\x83\x46\x25\xd2\x79\x04\x5c\x14\x09\x50\x38\xa3\xeb\xcb\xd1\x63\x53\xa9\x5f\x04\x7b\xed\x0a\x80\x1b\x83\x66\x98\x58\x6c\x8b\x9b\xb5\x8e\xce\xf9\x3c\xc4\xa2\x20\x35\xfa\x36\xaa\x6e\x9f\x38\xaa\xea\x2c\xd3\xe5\xfd\xbb\x86\x5d\xa2\x37\xc9\x94\x1b\x6a\x82\xe4\x15\x9f\xea\x2c\xb1\x95\xcc\x4f\x9f\x87\x19\x41\x1f\xa4\x8a\xb3\x92\x4d\xe5\xfd\xfb\xd3\xe7\x36\x02\xf8\x07\xc6\xa2\xb4\x54\x6f\x92\xc6\xf7\x1d\xbc\x7d\xf3\xea\x07\x72\x54\x7f\x22\xa8\x9b\xc0\x2b\x10\x99\xf4\x93\x0a\x4f\x2c\xdf\xf6\xb5\x28\x63\xae\xb9\x97\xca\x51\x9f\x4d\xf6\x99\x62\x56\x50\xe8\xb9\x41\xb0\xa5\x09\xd4\x11\x60\xde\xe5\xa4\x00\x89\xe6\x1a\x75\x8a\x8e\xec\x70\x92\x71\xf7\xfd\x49\x72\x44\x77\x53\xbc\xa2\xdb\xee\xb6\xd8\xab\xb4\xdd\x18\xeb\x71\x88\x41\x2b\x9d\xf1\x0e\x8d\x71\x4c\x3e\xda\x9a\x0d\x36\x8f\x74\x98\x77\xd8\xda\x02\x55\xbd\x93\xea\x7a\xd5\x98\x10\x69\x4e\xc8\xcc\x72\xdc\x21\x67\x15\xd4\x95\xb8\xba\xd9\xf1\x01\xa7\x6d\x86\x92\x07\x64\x50\x4d\x31\x23\x18\x0c\x06\xa1\x21\x71\xa6\xa4\x9e\x32\xe8\x2e\x09\x71\x36\x04\x76\xb2\x06\xe1\x2d\xc0\x18\x31\x07\xe1\xc7\x29\x3e\x06\x14\xc2\xa5\x10\x79\xa1\x46\x0d\x93\x11\x2c\x36\x85\x6c\x21\x2f\xb5\x0e\x62\xf5\x08\x7f\x65\x46\x87\x43\x78\x57\x8f\x74\x5a\x82\x0e\xd1\x9d\x73\xde\x44\xeb\x7d\xbb\xc8\x53\x54\x5d\xfe\x4e\xe9\x99\xea\x22\x81\x71\x0a\x83\x23\xb8\xea\x3d\xbb\x15\x32\x13\xe3\x0c\xaf\x7a\x7d\xb8\xea\x9d\x19\x3d\x35\x68\xad\x54\x53\x5a\x20\x63\xbc\xea\x3d\xc7\xa9\x11\x09\x26\x57\xbd\x0a\xf4\xe7\x85\x70\x71\xfa\x1a\xcd\x14\xbf\xc3\xf9\x13\x06\xb8\xb0\x75\xee\x8c\x70\x38\x9d\x3f\xc9\xe9\x4c\xbd\x97\x49\xeb\x2e\xe6\x05\x3e\xe1\xa4\xdb\x5a\x7c\x2d\x8a\x05\x40\xb5\x5a\x2d\x5c\x5e\xe7\xe8\xc4\xed\x51\xd4\xa8\xfa\xa7\x9f\xad\x56\xa3\xab\x5e\xc3\x53\x5f\xe7\x64\x2e\x85\x9b\x5f\xf5\x60\x81\x82\xd1\x55\x8f\x69\xa8\xd6\x2b\xa2\x47\x57\x3d\xc2\x46\xcb\x46\x3b\x3d\x2e\x27\xa3\xab\xde\x78\xee\xd0\xf6\x8f\xfa\x06\x8b\x3e\x39\xe1\x93\x06\xc3\x55\xef\x27\xb8\x52\x15\xd1\xda\xa5\x68\xbc\xa6\x2d\xfc\xd6\x5b\x8d\xb0\x1b\xa2\x2f\x40\x26\xac\xbb\x30\x42\x59\x59\x4d\xb5\xbb\x4e\x2d\x99\xfa\xea\xa5\x6a\xec\x4b\x3b\xbe\x94\x08\xdd\x7c\x10\x93\xab\x4f\x93\xdd\x1a\x9d\xb3\x3b\x78\x7b\xe0\x91\x83\x62\x36\xaa\xe6\xdb\xe7\x9e\x31\xfa\xba\x81\x40\x95\x2a\x41\x93\xcd\x39\x4f\x37\x7e\xc6\xc5\x43\x12\x01\x9c\x4e\x7c\xdc\x0a\xcd\xf4\x0d\xd9\x1b\x05\x46\x54\x50\xda\xaa\x62\x60\xba\x6a\x88\xe4\x67\xde\x3f\x02\x18\x0e\xa1\x31\x55\xca\x64\x84\x5d\xe1\x0d\xc8\xe5\x72\xe1\x46\x40\xa5\xde\x80\xe0\x75\x9e\xda\x98\x2f\x00\x72\xb4\x56\x4c\x77\x11\x74\x38\xe9\x73\x47\x5a\xe6\x42\x81\x41\x91\x10\x7d\xcd\x9e\x4a\x64\x2c\xb8\x12\xaa\xc2\x8d\x18\xeb\xd2\x07\x80\x46\xee\x41\xb4\xb9\x98\x93\x5c\x29\xfd\x93\x89\x56\x79\xa2\x93\x94\x5c\xdc\xbd\x42\x35\x75\xe9\x08\xbe\x38\xfe\xeb\x57\x5f\x3f\x84\xd7\x2a\x20\x7f\x8b\x0a\x8d\xe8\x2a\xc9\x3b\xd8\x5e\xbd\xd4\x9a\x28\x33\x5f\x51\x35\x60\x8d\xa6\xcd\x19\x3f\x32\x5a\xb0\xbb\x99\xb0\x54\x3c\xc3\x58\x58\x4c\xa0\x2c\x48\x0e\x14\xf4\xaa\xb2\x8a\xfb\xc6\x4e\x60\xd2\xb6\x0a\xc2\xa3\xe3\x3e\x8c\x83\x48\x57\xa3\xd8\xe5\xdd\x75\xd4\x41\xb2\xb4\xf0\x4d\x7f\x89\x1e\x2a\x47\x4b\x4e\x00\xdc\x2c\x70\xf1\x46\xd5\x61\x98\xf0\xac\xc9\x0a\x4d\x19\xb8\xd9\x2a\xa5\x72\x5f\x7d\xd9\xad\x4a\xa9\x64\x5e\xe6\x23\x78\xbc\x41\x89\x94\x58\xa6\x68\x3a\x4e\x18\x14\x76\x27\xcd\xf9\x83\x4d\x02\x14\x14\x7e\xa6\x46\xe4\xb9\x70\x32\x06\x99\x50\x2b\x3d\x91\xdc\x0a\xd5\x66\xeb\x7b\x5a\xbe\x58\xb5\x0e\xb5\xc4\xf6\x6d\x88\x29\x2d\x43\x3e\x33\x3a\x29\x63\x2a\xa1\xf5\xa4\x19\x3b\xb7\x82\xcd\xbc\x40\x6f\xe9\xbe\x34\x00\xbc\x23\x01\xd7\x2f\x62\xfc\xbb\x1a\x14\x54\xe3\xdb\x80\xb2\x2a\x98\x7d\xa2\x99\xa5\xc8\x51\x95\x5f\x2b\x85\x3b\x86\xa9\xb2\x32\xe1\xca\x57\xc0\xb4\x14\x46\x28\x87\x98\xf0\x3b\x2d\xb8\xa8\xce\xb6\xc2\x97\x68\x5e\x4f\xd4\x15\xd9\x45\x53\x9c\x13\x89\xe1\x95\x06\x7b\xe3\x56\x37\x3c\x7a\x7c\xbc\x56\xbf\xf5\x99\xce\x03\x85\x70\x0e\x8d\x1a\xc1\x8f\x97\xcf\x06\xff\x16\x83\x5f\xae\x0f\xc2\x3f\x8f\x07\xdf\xfc\xa7\x3f\xba\x7e\xd4\xfa\x79\x7d\xf8\xf4\x2f\x0f\x71\xf6\xf5\x35\xf9\x92\x99\x84\xc0\xdf\x0c\x7d\xbd\xe6\xfa\x9c\x15\xf4\x04\x2e\x4c\x89\x7d\x78\x29\x32\x8b\x7d\x78\xaf\x38\x9c\x77\x0b\x07\x55\x99\x77\x23\x1c\x40\x8f\xc0\xac\x26\xc4\xb0\xc9\xd0\xd7\xed\x06\x9c\x0f\x11\x02\x6f\x6f\x17\x01\xd7\x17\x7a\xd2\x8e\x0d\xad\x97\x59\x3c\xe4\x26\x77\xd0\x51\xa8\xcf\xa2\x58\xe7\xc3\xd6\xcb\x2e\x2a\x0c\x5f\x0b\x35\x87\x26\x10\xf9\x6a\x6a\xd9\x5e\xad\xaf\xf4\x63\xa3\xad\xad\xc7\x6a\x96\xe7\xf5\x50\x97\x5c\x3e\xbc\x8d\x43\xa7\x21\xcc\x58\x3a\x23\xcc\xbc\x55\x12\x57\x83\x90\xd2\xe2\xa4\xcc\xe0\xc0\x22\x42\xa4\x74\x82\xab\xf1\xf0\xd0\x47\x3d\x31\x96\x99\x74\x3c\x34\x4f\x90\xdb\x06\x19\x0a\xd8\xbc\xd0\xc6\x09\xe5\xbc\xd3\x18\x9c\xe2\x1d\xb5\x92\x39\x15\x45\xc8\xad\xcc\x41\xa2\xec\xd1\xd1\xf1\x17\xe7\xe5\x38\xd1\xb9\x90\xea\x65\xee\x86\x87\x4f\x0f\x3e\x94\x22\xe3\x01\x3f\xf5\x8c\x2f\x73\x77\xb8\x35\x71\x1d\x7d\xb5\xc5\x1f\x0e\x2e\xbd\xd5\x5f\x1f\x5c\x0e\xc2\x7f\x8f\xaa\xa5\xc3\xa7\x07\x57\xd1\xc6\xfd\xc3\x47\x44\x56\xcb\x97\xae\x2f\x07\x8d\x23\x45\xd7\x8f\x0e\x9f\xb6\xf6\x0e\x1f\xe0\x56\x06\x3f\x94\xd2\x60\x47\x93\x39\xe8\x28\xc4\x3a\x0e\x85\x42\xa1\x63\xc7\x07\xdd\x8e\x0d\xaf\xd2\x8e\x0d\xa2\x74\xcd\x94\xae\x63\x14\x57\x6d\x71\x4f\xb2\x32\xa4\x3b\xef\x8c\x16\xbb\x0d\x06\x17\x3b\xaf\xb3\x1a\x1a\xb4\x5f\xf7\xf3\xab\xb5\x3a\xd2\x84\xc9\xde\x95\x22\xa3\xb3\x7e\xec\xe7\xdf\xb3\x71\xa6\xf5\x59\xa1\x49\x33\xb6\x2a\xb1\x57\x9f\x8f\xf0\x06\x6f\xd1\xd4\xe3\x1a\xf8\xb8\xe6\x60\x73\x61\xf3\x73\xeb\x4f\xbc\x30\x46\x1b\x3e\xff\xb7\x01\x3f\x7f\xe7\xe5\x33\xf4\xa3\xa3\x36\xa4\x1f\xb7\x60\x5a\x87\xf1\x76\xcd\xfe\xe7\x1e\xe1\xa0\xfa\x3b\xf8\xfc\xf7\x1e\x5c\xa6\xe8\x76\x2d\x45\x1f\xe1\xa5\x70\x22\x03\x64\xf6\x3f\x2e\x5c\x3c\xd1\x14\xfb\x1c\x77\x62\x1f\x1f\xd2\xdb\xbc\xf7\x9f\x0a\x34\x9f\xeb\xfc\x8e\xb2\x5e\x95\x19\x07\xcb\x11\x38\x53\x7e\xfa\xca\x7f\xcb\xdd\x75\x2f\xb8\xb6\x5e\x2c\x52\x61\xbb\x05\xb4\x76\xb0\xe1\x9f\x05\x27\x3b\x23\x28\xbb\x38\x19\x9d\x5b\x03\x70\xb3\xba\xfc\xb3\x51\x44\x3b\xf1\xeb\x9f\xf5\xe2\xba\x07\x90\x4d\x05\x8d\x7f\x3e\xfd\xb0\xf1\x9e\x04\x62\xb1\x91\xbe\x8d\x0a\xee\x60\xe1\xdc\x61\xb1\x83\x96\x09\xef\x46\xa0\xbb\xa8\xda\x3f\x3b\x28\xdc\x3f\x3b\x09\xc4\x3f\xdb\x94\x7f\x6f\x80\xdb\x0d\xc1\x3f\x7f\x9c\x39\xdc\x93\xe4\x0d\x39\x79\xf5\xd8\x6a\x7e\xbe\x07\xa0\xcd\x20\x76\x6e\x09\x3e\x91\xb0\xb6\x08\x68\xcd\xb0\xfe\xff\x74\x5c\xbf\x45\x5c\x1b\x54\xbf\xd8\xcd\x65\x32\xc6\xf0\x59\x10\xb5\xb2\x8a\xdf\x59\xf2\xbb\x55\xea\x2a\x66\xc4\x08\x7f\xba\x47\x42\xf0\x87\xab\x4e\x43\x9b\x04\x0d\xb7\xf1\xf8\xa1\xf4\x2f\xf4\x15\xcc\x45\x9e\xf1\xfc\xa5\x69\xb7\xad\x9c\x2a\xea\xf2\x85\x72\x30\xe3\x77\x9a\x0c\x5e\xba\x7d\x1e\xf8\x3d\xf8\x5d\xc3\xd2\x52\xf3\xbd\x6f\xf8\xb4\xb8\x5e\x62\x13\x1e\x84\x8f\x7c\x9b\x5d\x00\x3f\xf6\x69\x95\x04\xd6\x69\x43\xf1\xcc\xaf\x34\xf6\xef\x47\x8b\xbe\x73\x59\xf8\xe8\xb7\xe7\xeb\x9a\xea\x9b\x5e\xfe\xd9\x7a\x15\x01\x97\xd7\x7b\x1e\x2a\x26\xdf\x57\xc4\xd0\xe2\x7f\x03\x00\x00\xff\xff\x1c\xbc\x32\x30\x25\x2d\x00\x00") func configCrdsKudoDev_instancesYamlBytes() ([]byte, error) { return bindataRead( diff --git a/test/e2e/readiness/00-assert.yaml b/test/e2e/readiness/00-assert.yaml new file mode 100644 index 000000000..329f38419 --- /dev/null +++ b/test/e2e/readiness/00-assert.yaml @@ -0,0 +1,16 @@ +apiVersion: kudo.dev/v1beta1 +kind: Instance +metadata: + name: first-operator +status: + conditions: + - type: Ready + status: "True" + planStatus: + deploy: + status: COMPLETE +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment \ No newline at end of file diff --git a/test/e2e/readiness/00-install.yaml b/test/e2e/readiness/00-install.yaml new file mode 100644 index 000000000..da568ad7d --- /dev/null +++ b/test/e2e/readiness/00-install.yaml @@ -0,0 +1,5 @@ +apiVersion: kudo.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl kudo install --instance first-operator ./first-operator + namespaced: true diff --git a/test/e2e/readiness/01-assert.yaml b/test/e2e/readiness/01-assert.yaml new file mode 100644 index 000000000..59d8f4178 --- /dev/null +++ b/test/e2e/readiness/01-assert.yaml @@ -0,0 +1,8 @@ +apiVersion: kudo.dev/v1beta1 +kind: Instance +metadata: + name: first-operator +status: + conditions: + - type: Ready + status: "False" \ No newline at end of file diff --git a/test/e2e/readiness/01-updatedeployment.yaml b/test/e2e/readiness/01-updatedeployment.yaml new file mode 100644 index 000000000..9fff1f0a3 --- /dev/null +++ b/test/e2e/readiness/01-updatedeployment.yaml @@ -0,0 +1,19 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment +spec: + selector: + matchLabels: + app: nginx + replicas: 2 + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: thisisnonexistingimage + ports: + - containerPort: 80 \ No newline at end of file diff --git a/test/e2e/readiness/first-operator/operator.yaml b/test/e2e/readiness/first-operator/operator.yaml new file mode 100644 index 000000000..b734f6ef3 --- /dev/null +++ b/test/e2e/readiness/first-operator/operator.yaml @@ -0,0 +1,25 @@ +apiVersion: kudo.dev/v1beta1 +name: "first-operator" +operatorVersion: "0.1.0" +appVersion: "1.7.9" +kubernetesVersion: 1.13.0 +maintainers: + - name: Your name + email: +url: https://kudo.dev +tasks: + - name: app + kind: Apply + spec: + resources: + - deployment.yaml +plans: + deploy: + strategy: serial + phases: + - name: main + strategy: parallel + steps: + - name: everything + tasks: + - app diff --git a/test/e2e/readiness/first-operator/params.yaml b/test/e2e/readiness/first-operator/params.yaml new file mode 100644 index 000000000..89c6d7726 --- /dev/null +++ b/test/e2e/readiness/first-operator/params.yaml @@ -0,0 +1,5 @@ +apiVersion: kudo.dev/v1beta1 +parameters: + - name: replicas + description: Number of replicas that should be run as part of the deployment + default: 2 diff --git a/test/e2e/readiness/first-operator/templates/deployment.yaml b/test/e2e/readiness/first-operator/templates/deployment.yaml new file mode 100644 index 000000000..f5450122d --- /dev/null +++ b/test/e2e/readiness/first-operator/templates/deployment.yaml @@ -0,0 +1,19 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment +spec: + selector: + matchLabels: + app: nginx + replicas: {{ .Params.replicas }} # tells deployment to run 2 pods matching the template + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:{{ .AppVersion }} + ports: + - containerPort: 80 \ No newline at end of file