From 729b4f443414159886b95448c1b15f1c8f0fe8d3 Mon Sep 17 00:00:00 2001 From: mikolaj-krzyzanowski-f3 Date: Tue, 7 Jan 2025 11:14:21 +0000 Subject: [PATCH] feat: Add MoveAZChaos --- api/v1alpha1/moveazchaos_types.go | 40 ++ api/v1alpha1/selector.go | 9 + api/v1alpha1/zz_generated.chaosmesh.go | 153 +++++++ api/v1alpha1/zz_generated.chaosmesh_test.go | 63 +++ api/v1alpha1/zz_generated.deepcopy.go | 148 +++++++ .../zz_generated.schedule.chaosmesh.go | 9 + .../zz_generated.workflow.chaosmesh.go | 22 + .../zz_generated.workflow.chaosmesh_test.go | 8 + .../crd/bases/chaos-mesh.org_moveazchaos.yaml | 147 +++++++ .../crd/bases/chaos-mesh.org_schedules.yaml | 80 ++++ .../bases/chaos-mesh.org_workflownodes.yaml | 106 +++++ .../crd/bases/chaos-mesh.org_workflows.yaml | 53 +++ config/crd/kustomization.yaml | 1 + controllers/chaosimpl/fx.go | 2 + controllers/chaosimpl/k8schaos/impl.go | 3 +- controllers/chaosimpl/moveazchaos/impl.go | 97 +++++ controllers/types/types.go | 8 + .../crds/chaos-mesh.org_moveazchaos.yaml | 147 +++++++ .../crds/chaos-mesh.org_schedules.yaml | 80 ++++ .../crds/chaos-mesh.org_workflownodes.yaml | 106 +++++ .../crds/chaos-mesh.org_workflows.yaml | 53 +++ manifests/crd.yaml | 386 ++++++++++++++++++ pkg/annotation/utils.go | 3 +- pkg/ctrl/server/generated/generated.go | 7 +- pkg/ctrl/server/model/models_gen.go | 3 +- pkg/ctrl/server/schema.resolvers.go | 9 +- pkg/dashboard/swaggerdocs/docs.go | 38 ++ pkg/dashboard/swaggerdocs/swagger.json | 38 ++ pkg/dashboard/swaggerdocs/swagger.yaml | 31 ++ pkg/selector/deployment/selector.go | 78 ++++ pkg/selector/selector.go | 3 + .../api/zz_generated.frontend.chaos-mesh.ts | 1 + 32 files changed, 1919 insertions(+), 13 deletions(-) create mode 100644 api/v1alpha1/moveazchaos_types.go create mode 100644 config/crd/bases/chaos-mesh.org_moveazchaos.yaml create mode 100644 controllers/chaosimpl/moveazchaos/impl.go create mode 100644 helm/chaos-mesh/crds/chaos-mesh.org_moveazchaos.yaml create mode 100644 pkg/selector/deployment/selector.go diff --git a/api/v1alpha1/moveazchaos_types.go b/api/v1alpha1/moveazchaos_types.go new file mode 100644 index 0000000000..1b0c3afde1 --- /dev/null +++ b/api/v1alpha1/moveazchaos_types.go @@ -0,0 +1,40 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var ( + _ InnerObject = (*MoveAZChaos)(nil) + _ InnerObjectWithSelector = (*MoveAZChaos)(nil) +) + +// +kubebuilder:object:root=true +// +chaos-mesh:experiment +type MoveAZChaos struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec MoveAZChaosSpec `json:"spec"` + Status MoveAZChaosStatus `json:"status"` +} + +type MoveAZChaosSpec struct { + DeploymentSelectorSpec `json:"selector"` + Zone string `json:"zone"` + // Duration represents the duration of the chaos + // +optional + Duration *string `json:"duration,omitempty"` + // RemoteCluster represents the remote cluster where the chaos will be deployed + // +optional + RemoteCluster string `json:"remoteCluster,omitempty"` +} +type MoveAZChaosStatus struct { + ChaosStatus `json:",inline"` +} + +func (obj *MoveAZChaos) GetSelectorSpecs() map[string]interface{} { + return map[string]interface{}{ + ".": &obj.Spec.DeploymentSelector, + } +} diff --git a/api/v1alpha1/selector.go b/api/v1alpha1/selector.go index 315bde4573..d71a0b0459 100644 --- a/api/v1alpha1/selector.go +++ b/api/v1alpha1/selector.go @@ -164,3 +164,12 @@ type NodeSelectorSpec struct { // +optional ExpressionSelectors LabelSelectorRequirements `json:"expressionSelectors,omitempty" swaggerignore:"true"` } + +type DeploymentSelector struct { + // Map of namespace names to a list of deployments in that namespace. + Deployments map[string][]string `json:"deployments,omitempty"` +} + +type DeploymentSelectorSpec struct { + DeploymentSelector `json:",inline"` +} diff --git a/api/v1alpha1/zz_generated.chaosmesh.go b/api/v1alpha1/zz_generated.chaosmesh.go index 87d947c290..f4331f6627 100644 --- a/api/v1alpha1/zz_generated.chaosmesh.go +++ b/api/v1alpha1/zz_generated.chaosmesh.go @@ -1987,6 +1987,148 @@ func (in *KernelChaos) Default() { gw.Default(in) } +const KindMoveAZChaos = "MoveAZChaos" + +// IsDeleted returns whether this resource has been deleted +func (in *MoveAZChaos) IsDeleted() bool { + return !in.DeletionTimestamp.IsZero() +} + +// IsPaused returns whether this resource has been paused +func (in *MoveAZChaos) IsPaused() bool { + if in.Annotations == nil || in.Annotations[PauseAnnotationKey] != "true" { + return false + } + return true +} + +// GetObjectMeta would return the ObjectMeta for chaos +func (in *MoveAZChaos) GetObjectMeta() *metav1.ObjectMeta { + return &in.ObjectMeta +} + +// GetDuration would return the duration for chaos +func (in *MoveAZChaosSpec) GetDuration() (*time.Duration, error) { + if in.Duration == nil { + return nil, nil + } + duration, err := time.ParseDuration(string(*in.Duration)) + if err != nil { + return nil, err + } + return &duration, nil +} + +// GetStatus returns the status +func (in *MoveAZChaos) GetStatus() *ChaosStatus { + return &in.Status.ChaosStatus +} + +// GetRemoteCluster returns the remoteCluster +func (in *MoveAZChaos) GetRemoteCluster() string { + return in.Spec.RemoteCluster +} + +// GetSpecAndMetaString returns a string including the meta and spec field of this chaos object. +func (in *MoveAZChaos) GetSpecAndMetaString() (string, error) { + spec, err := json.Marshal(in.Spec) + if err != nil { + return "", err + } + + meta := in.ObjectMeta.DeepCopy() + meta.SetResourceVersion("") + meta.SetGeneration(0) + + return string(spec) + meta.String(), nil +} + +// +kubebuilder:object:root=true + +// MoveAZChaosList contains a list of MoveAZChaos +type MoveAZChaosList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []MoveAZChaos `json:"items"` +} + +func (in *MoveAZChaosList) DeepCopyList() GenericChaosList { + return in.DeepCopy() +} + +// ListChaos returns a list of chaos +func (in *MoveAZChaosList) ListChaos() []GenericChaos { + var result []GenericChaos + for _, item := range in.Items { + item := item + result = append(result, &item) + } + return result +} + +func (in *MoveAZChaos) DurationExceeded(now time.Time) (bool, time.Duration, error) { + duration, err := in.Spec.GetDuration() + if err != nil { + return false, 0, err + } + + if duration != nil { + stopTime := in.GetCreationTimestamp().Add(*duration) + if stopTime.Before(now) { + return true, 0, nil + } + + return false, stopTime.Sub(now), nil + } + + return false, 0, nil +} + +func (in *MoveAZChaos) IsOneShot() bool { + if true { + return true + } + + return false +} + +var MoveAZChaosWebhookLog = logf.Log.WithName("MoveAZChaos-resource") + +func (in *MoveAZChaos) ValidateCreate() (admission.Warnings, error) { + MoveAZChaosWebhookLog.V(1).Info("validate create", "name", in.Name) + return in.Validate() +} + +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (in *MoveAZChaos) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + MoveAZChaosWebhookLog.V(1).Info("validate update", "name", in.Name) + if !reflect.DeepEqual(in.Spec, old.(*MoveAZChaos).Spec) { + return nil, ErrCanNotUpdateChaos + } + return in.Validate() +} + +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (in *MoveAZChaos) ValidateDelete() (admission.Warnings, error) { + MoveAZChaosWebhookLog.V(1).Info("validate delete", "name", in.Name) + + // Nothing to do? + return nil, nil +} + +var _ webhook.Validator = &MoveAZChaos{} + +func (in *MoveAZChaos) Validate() ([]string, error) { + errs := gw.Validate(in) + return nil, gw.Aggregate(errs) +} + +var _ webhook.Defaulter = &MoveAZChaos{} + +func (in *MoveAZChaos) Default() { + gw.Default(in) +} + const KindNetworkChaos = "NetworkChaos" // IsDeleted returns whether this resource has been deleted @@ -3410,6 +3552,12 @@ func init() { list: &KernelChaosList{}, }) + SchemeBuilder.Register(&MoveAZChaos{}, &MoveAZChaosList{}) + all.register(KindMoveAZChaos, &ChaosKind{ + chaos: &MoveAZChaos{}, + list: &MoveAZChaosList{}, + }) + SchemeBuilder.Register(&NetworkChaos{}, &NetworkChaosList{}) all.register(KindNetworkChaos, &ChaosKind{ chaos: &NetworkChaos{}, @@ -3541,6 +3689,11 @@ func init() { list: &KernelChaosList{}, }) + allScheduleItem.register(KindMoveAZChaos, &ChaosKind{ + chaos: &MoveAZChaos{}, + list: &MoveAZChaosList{}, + }) + allScheduleItem.register(KindNetworkChaos, &ChaosKind{ chaos: &NetworkChaos{}, list: &NetworkChaosList{}, diff --git a/api/v1alpha1/zz_generated.chaosmesh_test.go b/api/v1alpha1/zz_generated.chaosmesh_test.go index 66f0fe86b3..f55a621ea4 100644 --- a/api/v1alpha1/zz_generated.chaosmesh_test.go +++ b/api/v1alpha1/zz_generated.chaosmesh_test.go @@ -907,6 +907,69 @@ func TestKernelChaosListChaos(t *testing.T) { chaos.ListChaos() } +func TestMoveAZChaosIsDeleted(t *testing.T) { + g := NewGomegaWithT(t) + + chaos := &MoveAZChaos{} + err := faker.FakeData(chaos) + + g.Expect(err).To(BeNil()) + + chaos.IsDeleted() +} + +func TestMoveAZChaosIsIsPaused(t *testing.T) { + g := NewGomegaWithT(t) + + chaos := &MoveAZChaos{} + err := faker.FakeData(chaos) + + g.Expect(err).To(BeNil()) + + chaos.IsPaused() +} + +func TestMoveAZChaosGetDuration(t *testing.T) { + g := NewGomegaWithT(t) + + chaos := &MoveAZChaos{} + err := faker.FakeData(chaos) + + g.Expect(err).To(BeNil()) + + chaos.Spec.GetDuration() +} + +func TestMoveAZChaosGetStatus(t *testing.T) { + g := NewGomegaWithT(t) + + chaos := &MoveAZChaos{} + err := faker.FakeData(chaos) + + g.Expect(err).To(BeNil()) + + chaos.GetStatus() +} + +func TestMoveAZChaosGetSpecAndMetaString(t *testing.T) { + g := NewGomegaWithT(t) + chaos := &MoveAZChaos{} + err := faker.FakeData(chaos) + g.Expect(err).To(BeNil()) + chaos.GetSpecAndMetaString() +} + +func TestMoveAZChaosListChaos(t *testing.T) { + g := NewGomegaWithT(t) + + chaos := &MoveAZChaosList{} + err := faker.FakeData(chaos) + + g.Expect(err).To(BeNil()) + + chaos.ListChaos() +} + func TestNetworkChaosIsDeleted(t *testing.T) { g := NewGomegaWithT(t) diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 2c53cf6dc5..4de2acd468 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1558,6 +1558,53 @@ func (in *DelaySpec) DeepCopy() *DelaySpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DeploymentSelector) DeepCopyInto(out *DeploymentSelector) { + *out = *in + if in.Deployments != nil { + in, out := &in.Deployments, &out.Deployments + *out = make(map[string][]string, len(*in)) + for key, val := range *in { + var outVal []string + if val == nil { + (*out)[key] = nil + } else { + inVal := (*in)[key] + in, out := &inVal, &outVal + *out = make([]string, len(*in)) + copy(*out, *in) + } + (*out)[key] = outVal + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentSelector. +func (in *DeploymentSelector) DeepCopy() *DeploymentSelector { + if in == nil { + return nil + } + out := new(DeploymentSelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DeploymentSelectorSpec) DeepCopyInto(out *DeploymentSelectorSpec) { + *out = *in + in.DeploymentSelector.DeepCopyInto(&out.DeploymentSelector) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentSelectorSpec. +func (in *DeploymentSelectorSpec) DeepCopy() *DeploymentSelectorSpec { + if in == nil { + return nil + } + out := new(DeploymentSelectorSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DiskFileSpec) DeepCopyInto(out *DiskFileSpec) { *out = *in @@ -1693,6 +1740,11 @@ func (in *EmbedChaos) DeepCopyInto(out *EmbedChaos) { *out = new(KernelChaosSpec) (*in).DeepCopyInto(*out) } + if in.MoveAZChaos != nil { + in, out := &in.MoveAZChaos, &out.MoveAZChaos + *out = new(MoveAZChaosSpec) + (*in).DeepCopyInto(*out) + } if in.NetworkChaos != nil { in, out := &in.NetworkChaos, &out.NetworkChaos *out = new(NetworkChaosSpec) @@ -3461,6 +3513,102 @@ func (in *MistakeSpec) DeepCopy() *MistakeSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MoveAZChaos) DeepCopyInto(out *MoveAZChaos) { + *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 MoveAZChaos. +func (in *MoveAZChaos) DeepCopy() *MoveAZChaos { + if in == nil { + return nil + } + out := new(MoveAZChaos) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MoveAZChaos) 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 *MoveAZChaosList) DeepCopyInto(out *MoveAZChaosList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]MoveAZChaos, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MoveAZChaosList. +func (in *MoveAZChaosList) DeepCopy() *MoveAZChaosList { + if in == nil { + return nil + } + out := new(MoveAZChaosList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MoveAZChaosList) 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 *MoveAZChaosSpec) DeepCopyInto(out *MoveAZChaosSpec) { + *out = *in + in.DeploymentSelectorSpec.DeepCopyInto(&out.DeploymentSelectorSpec) + if in.Duration != nil { + in, out := &in.Duration, &out.Duration + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MoveAZChaosSpec. +func (in *MoveAZChaosSpec) DeepCopy() *MoveAZChaosSpec { + if in == nil { + return nil + } + out := new(MoveAZChaosSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MoveAZChaosStatus) DeepCopyInto(out *MoveAZChaosStatus) { + *out = *in + in.ChaosStatus.DeepCopyInto(&out.ChaosStatus) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MoveAZChaosStatus. +func (in *MoveAZChaosStatus) DeepCopy() *MoveAZChaosStatus { + if in == nil { + return nil + } + out := new(MoveAZChaosStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NetworkBandwidthSpec) DeepCopyInto(out *NetworkBandwidthSpec) { *out = *in diff --git a/api/v1alpha1/zz_generated.schedule.chaosmesh.go b/api/v1alpha1/zz_generated.schedule.chaosmesh.go index 114e77d5e1..1896c00338 100644 --- a/api/v1alpha1/zz_generated.schedule.chaosmesh.go +++ b/api/v1alpha1/zz_generated.schedule.chaosmesh.go @@ -38,6 +38,7 @@ const ( ScheduleTypeJVMChaos ScheduleTemplateType = "JVMChaos" ScheduleTypeK8SChaos ScheduleTemplateType = "K8SChaos" ScheduleTypeKernelChaos ScheduleTemplateType = "KernelChaos" + ScheduleTypeMoveAZChaos ScheduleTemplateType = "MoveAZChaos" ScheduleTypeNetworkChaos ScheduleTemplateType = "NetworkChaos" ScheduleTypePhysicalMachineChaos ScheduleTemplateType = "PhysicalMachineChaos" ScheduleTypePodChaos ScheduleTemplateType = "PodChaos" @@ -65,6 +66,7 @@ var allScheduleTemplateType = []ScheduleTemplateType{ ScheduleTypeJVMChaos, ScheduleTypeK8SChaos, ScheduleTypeKernelChaos, + ScheduleTypeMoveAZChaos, ScheduleTypeNetworkChaos, ScheduleTypePhysicalMachineChaos, ScheduleTypePodChaos, @@ -135,6 +137,10 @@ func (it *ScheduleItem) SpawnNewObject(templateType ScheduleTemplateType) (Gener result := KernelChaos{} result.Spec = *it.KernelChaos return &result, nil + case ScheduleTypeMoveAZChaos: + result := MoveAZChaos{} + result.Spec = *it.MoveAZChaos + return &result, nil case ScheduleTypeNetworkChaos: result := NetworkChaos{} result.Spec = *it.NetworkChaos @@ -221,6 +227,9 @@ func (it *ScheduleItem) RestoreChaosSpec(root interface{}) error { case *KernelChaos: *it.KernelChaos = chaos.Spec return nil + case *MoveAZChaos: + *it.MoveAZChaos = chaos.Spec + return nil case *NetworkChaos: *it.NetworkChaos = chaos.Spec return nil diff --git a/api/v1alpha1/zz_generated.workflow.chaosmesh.go b/api/v1alpha1/zz_generated.workflow.chaosmesh.go index 37d54b71da..f73cc0270c 100644 --- a/api/v1alpha1/zz_generated.workflow.chaosmesh.go +++ b/api/v1alpha1/zz_generated.workflow.chaosmesh.go @@ -38,6 +38,7 @@ const ( TypeJVMChaos TemplateType = "JVMChaos" TypeK8SChaos TemplateType = "K8SChaos" TypeKernelChaos TemplateType = "KernelChaos" + TypeMoveAZChaos TemplateType = "MoveAZChaos" TypeNetworkChaos TemplateType = "NetworkChaos" TypePhysicalMachineChaos TemplateType = "PhysicalMachineChaos" TypePodChaos TemplateType = "PodChaos" @@ -65,6 +66,7 @@ var allChaosTemplateType = []TemplateType{ TypeJVMChaos, TypeK8SChaos, TypeKernelChaos, + TypeMoveAZChaos, TypeNetworkChaos, TypePhysicalMachineChaos, TypePodChaos, @@ -106,6 +108,8 @@ type EmbedChaos struct { // +optional KernelChaos *KernelChaosSpec `json:"kernelChaos,omitempty"` // +optional + MoveAZChaos *MoveAZChaosSpec `json:"moveazChaos,omitempty"` + // +optional NetworkChaos *NetworkChaosSpec `json:"networkChaos,omitempty"` // +optional PhysicalMachineChaos *PhysicalMachineChaosSpec `json:"physicalmachineChaos,omitempty"` @@ -182,6 +186,10 @@ func (it *EmbedChaos) SpawnNewObject(templateType TemplateType) (GenericChaos, e result := KernelChaos{} result.Spec = *it.KernelChaos return &result, nil + case TypeMoveAZChaos: + result := MoveAZChaos{} + result.Spec = *it.MoveAZChaos + return &result, nil case TypeNetworkChaos: result := NetworkChaos{} result.Spec = *it.NetworkChaos @@ -264,6 +272,9 @@ func (it *EmbedChaos) RestoreChaosSpec(root interface{}) error { case *KernelChaos: *it.KernelChaos = chaos.Spec return nil + case *MoveAZChaos: + *it.MoveAZChaos = chaos.Spec + return nil case *NetworkChaos: *it.NetworkChaos = chaos.Spec return nil @@ -338,6 +349,9 @@ func (it *EmbedChaos) SpawnNewList(templateType TemplateType) (GenericChaosList, case TypeKernelChaos: result := KernelChaosList{} return &result, nil + case TypeMoveAZChaos: + result := MoveAZChaosList{} + return &result, nil case TypeNetworkChaos: result := NetworkChaosList{} return &result, nil @@ -480,6 +494,14 @@ func (in *KernelChaosList) GetItems() []GenericChaos { } return result } +func (in *MoveAZChaosList) GetItems() []GenericChaos { + var result []GenericChaos + for _, item := range in.Items { + item := item + result = append(result, &item) + } + return result +} func (in *NetworkChaosList) GetItems() []GenericChaos { var result []GenericChaos for _, item := range in.Items { diff --git a/api/v1alpha1/zz_generated.workflow.chaosmesh_test.go b/api/v1alpha1/zz_generated.workflow.chaosmesh_test.go index ac84c8a8b8..51676dc752 100644 --- a/api/v1alpha1/zz_generated.workflow.chaosmesh_test.go +++ b/api/v1alpha1/zz_generated.workflow.chaosmesh_test.go @@ -135,6 +135,14 @@ func TestChaosKindMapShouldContainsKernelChaos(t *testing.T) { _, ok := all.kinds[string(requiredType)] g.Expect(ok).To(Equal(true), "all kinds map should contains this type", requiredType) } +func TestChaosKindMapShouldContainsMoveAZChaos(t *testing.T) { + g := NewGomegaWithT(t) + var requiredType TemplateType + requiredType = TypeMoveAZChaos + + _, ok := all.kinds[string(requiredType)] + g.Expect(ok).To(Equal(true), "all kinds map should contains this type", requiredType) +} func TestChaosKindMapShouldContainsNetworkChaos(t *testing.T) { g := NewGomegaWithT(t) var requiredType TemplateType diff --git a/config/crd/bases/chaos-mesh.org_moveazchaos.yaml b/config/crd/bases/chaos-mesh.org_moveazchaos.yaml new file mode 100644 index 0000000000..c99b8b88b5 --- /dev/null +++ b/config/crd/bases/chaos-mesh.org_moveazchaos.yaml @@ -0,0 +1,147 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: moveazchaos.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: MoveAZChaos + listKind: MoveAZChaosList + plural: moveazchaos + singular: moveazchaos + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + 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: + properties: + duration: + description: Duration represents the duration of the chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list of deployments in + that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object + status: + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + - status + type: object + served: true + storage: true diff --git a/config/crd/bases/chaos-mesh.org_schedules.yaml b/config/crd/bases/chaos-mesh.org_schedules.yaml index d1c6d60e1b..d0a634d937 100644 --- a/config/crd/bases/chaos-mesh.org_schedules.yaml +++ b/config/crd/bases/chaos-mesh.org_schedules.yaml @@ -1898,6 +1898,32 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration of the chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list of deployments + in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object networkChaos: description: NetworkChaosSpec defines the desired state of NetworkChaos properties: @@ -5968,6 +5994,33 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration of the + chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list of + deployments in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object name: type: string networkChaos: @@ -9825,6 +9878,33 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration of + the chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list + of deployments in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object networkChaos: description: NetworkChaosSpec defines the desired state of NetworkChaos diff --git a/config/crd/bases/chaos-mesh.org_workflownodes.yaml b/config/crd/bases/chaos-mesh.org_workflownodes.yaml index 86c8a1f84c..49546f4f22 100644 --- a/config/crd/bases/chaos-mesh.org_workflownodes.yaml +++ b/config/crd/bases/chaos-mesh.org_workflownodes.yaml @@ -1919,6 +1919,32 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration of the chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list of deployments + in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object networkChaos: description: NetworkChaosSpec defines the desired state of NetworkChaos properties: @@ -5533,6 +5559,32 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration of the chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list of deployments + in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object networkChaos: description: NetworkChaosSpec defines the desired state of NetworkChaos properties: @@ -9699,6 +9751,33 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration of + the chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list + of deployments in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object name: type: string networkChaos: @@ -13684,6 +13763,33 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration + of the chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a + list of deployments in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object networkChaos: description: NetworkChaosSpec defines the desired state of NetworkChaos diff --git a/config/crd/bases/chaos-mesh.org_workflows.yaml b/config/crd/bases/chaos-mesh.org_workflows.yaml index 9144cef58b..040c4a1cdc 100644 --- a/config/crd/bases/chaos-mesh.org_workflows.yaml +++ b/config/crd/bases/chaos-mesh.org_workflows.yaml @@ -1990,6 +1990,32 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration of the chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list of deployments + in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object name: type: string networkChaos: @@ -5743,6 +5769,33 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration of the + chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list of + deployments in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object networkChaos: description: NetworkChaosSpec defines the desired state of NetworkChaos diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 3d3ecc1990..d0fd943e6a 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -34,6 +34,7 @@ resources: - bases/chaos-mesh.org_resourcescalechaos.yaml - bases/chaos-mesh.org_podpvcchaos.yaml - bases/chaos-mesh.org_certificatechaos.yaml +- bases/chaos-mesh.org_moveazchaos.yaml # +kubebuilder:scaffold:crdkustomizeresource patchesStrategicMerge: diff --git a/controllers/chaosimpl/fx.go b/controllers/chaosimpl/fx.go index 44cc6b9b5e..444fe86585 100644 --- a/controllers/chaosimpl/fx.go +++ b/controllers/chaosimpl/fx.go @@ -32,6 +32,7 @@ import ( "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/jvmchaos" "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/k8schaos" "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/kernelchaos" + "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/moveazchaos" "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/networkchaos" "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/physicalmachinechaos" "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/podchaos" @@ -66,5 +67,6 @@ var AllImpl = fx.Options( rollingrestartchaos.Module, podpvcchaos.Module, certificatechaos.Module, + moveazchaos.Module, utils.Module) diff --git a/controllers/chaosimpl/k8schaos/impl.go b/controllers/chaosimpl/k8schaos/impl.go index ad1eea2878..a1e9113eb8 100644 --- a/controllers/chaosimpl/k8schaos/impl.go +++ b/controllers/chaosimpl/k8schaos/impl.go @@ -23,7 +23,7 @@ import ( "github.com/go-logr/logr" "go.uber.org/fx" - "gopkg.in/yaml.v3" + "gopkg.in/yaml.v2" apiErrors "k8s.io/apimachinery/pkg/api/errors" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -32,6 +32,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + impltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" ) diff --git a/controllers/chaosimpl/moveazchaos/impl.go b/controllers/chaosimpl/moveazchaos/impl.go new file mode 100644 index 0000000000..652b78e413 --- /dev/null +++ b/controllers/chaosimpl/moveazchaos/impl.go @@ -0,0 +1,97 @@ +package moveazchaos + +import ( + "context" + "errors" + "fmt" + + "github.com/go-logr/logr" + "go.uber.org/fx" + v1 "k8s.io/api/apps/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + + chaosimpltypes "github.com/chaos-mesh/chaos-mesh/controllers/chaosimpl/types" + "github.com/chaos-mesh/chaos-mesh/controllers/utils/controller" +) + +type Impl struct { + client.Client + Log logr.Logger +} + +func (i *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) { + moveAz, ok := obj.(*v1alpha1.MoveAZChaos) + + if !ok { + err := errors.New("not MoveAZChaos") + i.Log.Error(err, "casting InnerObject to MoveAZChaos") + return v1alpha1.NotInjected, err + } + + name, err := controller.ParseNamespacedName(records[index].Id) + if err != nil { + i.Log.Error(err, "parsing record name") + return v1alpha1.NotInjected, err + } + + var deployment v1.Deployment + err = i.Client.Get(ctx, name, &deployment) + if err != nil { + i.Log.Error(err, "getting deployment") + return v1alpha1.NotInjected, err + } + + data := []byte(fmt.Sprintf(`{"spec": {"template": {"spec": {"nodeSelector": {"topology.kubernetes.io/zone" :"%s"}}}}}`, moveAz.Spec.Zone)) + patch := client.RawPatch(types.MergePatchType, data) + err = i.Client.Patch(ctx, &deployment, patch) + if err != nil { + i.Log.Error(err, "patching deployment") + return v1alpha1.NotInjected, err + } + + return v1alpha1.Injected, nil +} + +func (i *Impl) Recover(ctx context.Context, index int, records []*v1alpha1.Record, _ v1alpha1.InnerObject) (v1alpha1.Phase, error) { + name, err := controller.ParseNamespacedName(records[index].Id) + if err != nil { + i.Log.Error(err, "parsing record name") + return v1alpha1.Injected, err + } + + var deployment v1.Deployment + err = i.Client.Get(ctx, name, &deployment) + if err != nil { + i.Log.Error(err, "getting deployment") + return v1alpha1.Injected, err + } + + data := []byte(`[{"op": "remove", "path": "/spec/template/spec/nodeSelector/topology.kubernetes.io~1zone"}]`) + patch := client.RawPatch(types.JSONPatchType, data) + err = i.Client.Patch(ctx, &deployment, patch) + if err != nil { + i.Log.Error(err, "patching deployment") + return v1alpha1.Injected, err + } + + return v1alpha1.NotInjected, nil +} + +func NewImpl(c client.Client, log logr.Logger) *chaosimpltypes.ChaosImplPair { + return &chaosimpltypes.ChaosImplPair{ + Name: "moveazchaos", + Object: &v1alpha1.MoveAZChaos{}, + Impl: &Impl{c, log.WithName("moveazchaos")}, + ObjectList: &v1alpha1.MoveAZChaosList{}, + } +} + +var Module = fx.Provide( + fx.Annotated{ + Group: "impl", + Target: NewImpl, + }, +) diff --git a/controllers/types/types.go b/controllers/types/types.go index 49eb2753b9..14b5b08b98 100644 --- a/controllers/types/types.go +++ b/controllers/types/types.go @@ -156,6 +156,14 @@ var ChaosObjects = fx.Supply( Object: &v1alpha1.CiliumChaos{}, }, }, + + fx.Annotated{ + Group: "objs", + Target: Object{ + Name: "moveazchaos", + Object: &v1alpha1.MoveAZChaos{}, + }, + }, ) // WebhookObject only used for registration the diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_moveazchaos.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_moveazchaos.yaml new file mode 100644 index 0000000000..c99b8b88b5 --- /dev/null +++ b/helm/chaos-mesh/crds/chaos-mesh.org_moveazchaos.yaml @@ -0,0 +1,147 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: moveazchaos.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: MoveAZChaos + listKind: MoveAZChaosList + plural: moveazchaos + singular: moveazchaos + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + 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: + properties: + duration: + description: Duration represents the duration of the chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list of deployments in + that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object + status: + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + - status + type: object + served: true + storage: true diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_schedules.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_schedules.yaml index d1c6d60e1b..d0a634d937 100644 --- a/helm/chaos-mesh/crds/chaos-mesh.org_schedules.yaml +++ b/helm/chaos-mesh/crds/chaos-mesh.org_schedules.yaml @@ -1898,6 +1898,32 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration of the chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list of deployments + in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object networkChaos: description: NetworkChaosSpec defines the desired state of NetworkChaos properties: @@ -5968,6 +5994,33 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration of the + chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list of + deployments in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object name: type: string networkChaos: @@ -9825,6 +9878,33 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration of + the chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list + of deployments in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object networkChaos: description: NetworkChaosSpec defines the desired state of NetworkChaos diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_workflownodes.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_workflownodes.yaml index 86c8a1f84c..49546f4f22 100644 --- a/helm/chaos-mesh/crds/chaos-mesh.org_workflownodes.yaml +++ b/helm/chaos-mesh/crds/chaos-mesh.org_workflownodes.yaml @@ -1919,6 +1919,32 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration of the chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list of deployments + in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object networkChaos: description: NetworkChaosSpec defines the desired state of NetworkChaos properties: @@ -5533,6 +5559,32 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration of the chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list of deployments + in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object networkChaos: description: NetworkChaosSpec defines the desired state of NetworkChaos properties: @@ -9699,6 +9751,33 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration of + the chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list + of deployments in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object name: type: string networkChaos: @@ -13684,6 +13763,33 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration + of the chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a + list of deployments in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object networkChaos: description: NetworkChaosSpec defines the desired state of NetworkChaos diff --git a/helm/chaos-mesh/crds/chaos-mesh.org_workflows.yaml b/helm/chaos-mesh/crds/chaos-mesh.org_workflows.yaml index 9144cef58b..040c4a1cdc 100644 --- a/helm/chaos-mesh/crds/chaos-mesh.org_workflows.yaml +++ b/helm/chaos-mesh/crds/chaos-mesh.org_workflows.yaml @@ -1990,6 +1990,32 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration of the chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list of deployments + in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object name: type: string networkChaos: @@ -5743,6 +5769,33 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration of the + chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list of + deployments in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object networkChaos: description: NetworkChaosSpec defines the desired state of NetworkChaos diff --git a/manifests/crd.yaml b/manifests/crd.yaml index 98c0717302..5622cfa7e0 100644 --- a/manifests/crd.yaml +++ b/manifests/crd.yaml @@ -3694,6 +3694,153 @@ spec: --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: moveazchaos.chaos-mesh.org +spec: + group: chaos-mesh.org + names: + kind: MoveAZChaos + listKind: MoveAZChaosList + plural: moveazchaos + singular: moveazchaos + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + 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: + properties: + duration: + description: Duration represents the duration of the chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where the + chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list of deployments in + that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object + status: + properties: + conditions: + description: Conditions represents the current global condition of + the chaos + items: + properties: + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + experiment: + description: Experiment records the last experiment state. + properties: + containerRecords: + description: Records are used to track the running status + items: + properties: + events: + description: Events are the essential details about the + injections and recoveries + items: + properties: + message: + description: Message is the detail message, e.g. the + reason why we failed to inject the chaos + type: string + operation: + description: Operation represents the operation we + are doing, when we crate this event + type: string + timestamp: + description: Timestamp is time when we create this + event + format: date-time + type: string + type: + description: Type means the stage of this event + type: string + required: + - operation + - timestamp + - type + type: object + type: array + id: + type: string + injectedCount: + description: InjectedCount is a counter to record the sum + of successful injections + type: integer + phase: + type: string + recoveredCount: + description: RecoveredCount is a counter to record the sum + of successful recoveries + type: integer + selectorKey: + type: string + required: + - id + - injectedCount + - phase + - recoveredCount + - selectorKey + type: object + type: array + desiredPhase: + enum: + - Run + - Stop + type: string + type: object + required: + - experiment + type: object + required: + - spec + - status + type: object + served: true + storage: true +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.13.0 @@ -8879,6 +9026,32 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration of the chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list of deployments + in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object networkChaos: description: NetworkChaosSpec defines the desired state of NetworkChaos properties: @@ -12949,6 +13122,33 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration of the + chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list of + deployments in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object name: type: string networkChaos: @@ -16806,6 +17006,33 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration of + the chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list + of deployments in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object networkChaos: description: NetworkChaosSpec defines the desired state of NetworkChaos @@ -27084,6 +27311,32 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration of the chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list of deployments + in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object networkChaos: description: NetworkChaosSpec defines the desired state of NetworkChaos properties: @@ -30698,6 +30951,32 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration of the chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster where + the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list of deployments + in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object networkChaos: description: NetworkChaosSpec defines the desired state of NetworkChaos properties: @@ -34864,6 +35143,33 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration of + the chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list + of deployments in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object name: type: string networkChaos: @@ -38849,6 +39155,33 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration + of the chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote + cluster where the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a + list of deployments in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object networkChaos: description: NetworkChaosSpec defines the desired state of NetworkChaos @@ -53500,6 +53833,32 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration of the chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list of deployments + in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object name: type: string networkChaos: @@ -57253,6 +57612,33 @@ spec: - mode - selector type: object + moveazChaos: + properties: + duration: + description: Duration represents the duration of the + chaos + type: string + remoteCluster: + description: RemoteCluster represents the remote cluster + where the chaos will be deployed + type: string + selector: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list of + deployments in that namespace. + type: object + type: object + zone: + type: string + required: + - selector + - zone + type: object networkChaos: description: NetworkChaosSpec defines the desired state of NetworkChaos diff --git a/pkg/annotation/utils.go b/pkg/annotation/utils.go index 1894f978f4..d6072866c6 100644 --- a/pkg/annotation/utils.go +++ b/pkg/annotation/utils.go @@ -32,7 +32,8 @@ func GenKeyForImage(pc *v1alpha1.PodChaos, containerName string, isInit bool) st } else { containerName += "-normal" } - imageKey := fmt.Sprintf("%s-%s-%s-%s-image", AnnotationPrefix, pc.Name, pc.Spec.Action, containerName) + imageKey := fmt.Sprintf("%s-%s-%s-%s-image", + AnnotationPrefix, pc.Name, pc.Spec.Action, containerName) // name part of annotation must be no more than 63 characters. // If the key is too long, we just use containerName as the key of annotation. diff --git a/pkg/ctrl/server/generated/generated.go b/pkg/ctrl/server/generated/generated.go index 5c858abc1f..f090020243 100644 --- a/pkg/ctrl/server/generated/generated.go +++ b/pkg/ctrl/server/generated/generated.go @@ -14,13 +14,12 @@ import ( "github.com/99designs/gqlgen/graphql" "github.com/99designs/gqlgen/graphql/introspection" + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/server/model" gqlparser "github.com/vektah/gqlparser/v2" "github.com/vektah/gqlparser/v2/ast" - v1 "k8s.io/api/core/v1" + "k8s.io/api/core/v1" v11 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" - "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/server/model" ) // region ************************** generated!.gotpl ************************** diff --git a/pkg/ctrl/server/model/models_gen.go b/pkg/ctrl/server/model/models_gen.go index deeb57aebd..24fbd67f5a 100644 --- a/pkg/ctrl/server/model/models_gen.go +++ b/pkg/ctrl/server/model/models_gen.go @@ -7,9 +7,8 @@ import ( "io" "strconv" - v1 "k8s.io/api/core/v1" - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" + "k8s.io/api/core/v1" ) type Cgroups struct { diff --git a/pkg/ctrl/server/schema.resolvers.go b/pkg/ctrl/server/schema.resolvers.go index 3bd2f6d4ef..94a35178b3 100644 --- a/pkg/ctrl/server/schema.resolvers.go +++ b/pkg/ctrl/server/schema.resolvers.go @@ -12,15 +12,14 @@ import ( "io" "time" - v1 "k8s.io/api/core/v1" - v11 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/server/generated" "github.com/chaos-mesh/chaos-mesh/pkg/ctrl/server/model" podSelector "github.com/chaos-mesh/chaos-mesh/pkg/selector/pod" + "k8s.io/api/core/v1" + v11 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" ) func (r *attrOverrideSpecResolver) Ino(ctx context.Context, obj *v1alpha1.AttrOverrideSpec) (*int, error) { diff --git a/pkg/dashboard/swaggerdocs/docs.go b/pkg/dashboard/swaggerdocs/docs.go index b39ee18c32..22f1a5ff23 100644 --- a/pkg/dashboard/swaggerdocs/docs.go +++ b/pkg/dashboard/swaggerdocs/docs.go @@ -5580,6 +5580,10 @@ const docTemplate = `{ "description": "+optional", "$ref": "#/definitions/v1alpha1.KernelChaosSpec" }, + "moveazChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.MoveAZChaosSpec" + }, "networkChaos": { "description": "+optional", "$ref": "#/definitions/v1alpha1.NetworkChaosSpec" @@ -6929,6 +6933,32 @@ const docTemplate = `{ } } }, + "v1alpha1.MoveAZChaosSpec": { + "type": "object", + "properties": { + "deployments": { + "description": "Map of namespace names to a list of deployments in that namespace.", + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "duration": { + "description": "Duration represents the duration of the chaos\n+optional", + "type": "string" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "zone": { + "type": "string" + } + } + }, "v1alpha1.NetworkBandwidthSpec": { "type": "object", "properties": { @@ -8197,6 +8227,10 @@ const docTemplate = `{ "description": "+optional", "$ref": "#/definitions/v1alpha1.KernelChaosSpec" }, + "moveazChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.MoveAZChaosSpec" + }, "networkChaos": { "description": "+optional", "$ref": "#/definitions/v1alpha1.NetworkChaosSpec" @@ -8581,6 +8615,10 @@ const docTemplate = `{ "description": "+optional", "$ref": "#/definitions/v1alpha1.KernelChaosSpec" }, + "moveazChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.MoveAZChaosSpec" + }, "name": { "type": "string" }, diff --git a/pkg/dashboard/swaggerdocs/swagger.json b/pkg/dashboard/swaggerdocs/swagger.json index f7c625587c..5cdce683ec 100644 --- a/pkg/dashboard/swaggerdocs/swagger.json +++ b/pkg/dashboard/swaggerdocs/swagger.json @@ -5572,6 +5572,10 @@ "description": "+optional", "$ref": "#/definitions/v1alpha1.KernelChaosSpec" }, + "moveazChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.MoveAZChaosSpec" + }, "networkChaos": { "description": "+optional", "$ref": "#/definitions/v1alpha1.NetworkChaosSpec" @@ -6921,6 +6925,32 @@ } } }, + "v1alpha1.MoveAZChaosSpec": { + "type": "object", + "properties": { + "deployments": { + "description": "Map of namespace names to a list of deployments in that namespace.", + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "duration": { + "description": "Duration represents the duration of the chaos\n+optional", + "type": "string" + }, + "remoteCluster": { + "description": "RemoteCluster represents the remote cluster where the chaos will be deployed\n+optional", + "type": "string" + }, + "zone": { + "type": "string" + } + } + }, "v1alpha1.NetworkBandwidthSpec": { "type": "object", "properties": { @@ -8189,6 +8219,10 @@ "description": "+optional", "$ref": "#/definitions/v1alpha1.KernelChaosSpec" }, + "moveazChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.MoveAZChaosSpec" + }, "networkChaos": { "description": "+optional", "$ref": "#/definitions/v1alpha1.NetworkChaosSpec" @@ -8573,6 +8607,10 @@ "description": "+optional", "$ref": "#/definitions/v1alpha1.KernelChaosSpec" }, + "moveazChaos": { + "description": "+optional", + "$ref": "#/definitions/v1alpha1.MoveAZChaosSpec" + }, "name": { "type": "string" }, diff --git a/pkg/dashboard/swaggerdocs/swagger.yaml b/pkg/dashboard/swaggerdocs/swagger.yaml index e0e5f107a1..c07587fae8 100644 --- a/pkg/dashboard/swaggerdocs/swagger.yaml +++ b/pkg/dashboard/swaggerdocs/swagger.yaml @@ -4022,6 +4022,9 @@ definitions: kernelChaos: $ref: '#/definitions/v1alpha1.KernelChaosSpec' description: +optional + moveazChaos: + $ref: '#/definitions/v1alpha1.MoveAZChaosSpec' + description: +optional networkChaos: $ref: '#/definitions/v1alpha1.NetworkChaosSpec' description: +optional @@ -5417,6 +5420,28 @@ definitions: +kubebuilder:validation:Minimum=1 type: integer type: object + v1alpha1.MoveAZChaosSpec: + properties: + deployments: + additionalProperties: + items: + type: string + type: array + description: Map of namespace names to a list of deployments in that namespace. + type: object + duration: + description: |- + Duration represents the duration of the chaos + +optional + type: string + remoteCluster: + description: |- + RemoteCluster represents the remote cluster where the chaos will be deployed + +optional + type: string + zone: + type: string + type: object v1alpha1.NetworkBandwidthSpec: properties: buffer: @@ -6808,6 +6833,9 @@ definitions: kernelChaos: $ref: '#/definitions/v1alpha1.KernelChaosSpec' description: +optional + moveazChaos: + $ref: '#/definitions/v1alpha1.MoveAZChaosSpec' + description: +optional networkChaos: $ref: '#/definitions/v1alpha1.NetworkChaosSpec' description: +optional @@ -7231,6 +7259,9 @@ definitions: kernelChaos: $ref: '#/definitions/v1alpha1.KernelChaosSpec' description: +optional + moveazChaos: + $ref: '#/definitions/v1alpha1.MoveAZChaosSpec' + description: +optional name: type: string networkChaos: diff --git a/pkg/selector/deployment/selector.go b/pkg/selector/deployment/selector.go new file mode 100644 index 0000000000..825dddd504 --- /dev/null +++ b/pkg/selector/deployment/selector.go @@ -0,0 +1,78 @@ +package deployment + +import ( + "context" + + v1 "k8s.io/api/apps/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/kubernetes" + ctrl "sigs.k8s.io/controller-runtime" + + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" +) + +type Deployment struct { + v1.Deployment +} + +func (d *Deployment) Id() string { + return (types.NamespacedName{ + Name: d.Name, + Namespace: d.Namespace, + }).String() +} + +type SelectImpl struct{} + +func (impl *SelectImpl) Select(ctx context.Context, selector *v1alpha1.DeploymentSelector) ([]*Deployment, error) { + if selector == nil { + return []*Deployment{}, nil + } + + client, err := kubernetesClient() + if err != nil { + return []*Deployment{}, err + } + + var deployments []*Deployment + for namespace, names := range selector.Deployments { + deploymentList, err := client.AppsV1().Deployments(namespace).List(ctx, metav1.ListOptions{}) + if err != nil { + return []*Deployment{}, err + } + + matched := match(deploymentList, names) + deployments = append(deployments, matched...) + + } + + return deployments, nil +} + +func match(list *v1.DeploymentList, names []string) []*Deployment { + var deployments []*Deployment + for _, selectorName := range names { + for _, deployment := range list.Items { + if selectorName == deployment.Name { + deployments = append(deployments, &Deployment{ + Deployment: deployment, + }) + } + } + } + + return deployments +} + +func kubernetesClient() (*kubernetes.Clientset, error) { + config, err := ctrl.GetConfig() + if err != nil { + return nil, err + } + return kubernetes.NewForConfig(config) +} + +func New() *SelectImpl { + return &SelectImpl{} +} diff --git a/pkg/selector/selector.go b/pkg/selector/selector.go index 2b81ad26a3..03282d5fac 100644 --- a/pkg/selector/selector.go +++ b/pkg/selector/selector.go @@ -28,6 +28,7 @@ import ( "github.com/chaos-mesh/chaos-mesh/pkg/selector/cloudstackhost" "github.com/chaos-mesh/chaos-mesh/pkg/selector/cloudstackvm" "github.com/chaos-mesh/chaos-mesh/pkg/selector/container" + "github.com/chaos-mesh/chaos-mesh/pkg/selector/deployment" "github.com/chaos-mesh/chaos-mesh/pkg/selector/gcp" "github.com/chaos-mesh/chaos-mesh/pkg/selector/k8schaos" "github.com/chaos-mesh/chaos-mesh/pkg/selector/node" @@ -91,6 +92,7 @@ type SelectorParams struct { RollingRestartSelector *rollingrestart.SelectImpl PodPVCSelector *podpvc.SelectImpl CertificateSelector *certificate.SelectImpl + DeploymentSelector *deployment.SelectImpl } func New(p SelectorParams) *Selector { @@ -128,4 +130,5 @@ var Module = fx.Provide( rollingrestart.New, podpvc.New, certificate.New, + deployment.New, ) diff --git a/ui/app/src/api/zz_generated.frontend.chaos-mesh.ts b/ui/app/src/api/zz_generated.frontend.chaos-mesh.ts index 4d6b2db87b..25514dedf0 100644 --- a/ui/app/src/api/zz_generated.frontend.chaos-mesh.ts +++ b/ui/app/src/api/zz_generated.frontend.chaos-mesh.ts @@ -15,6 +15,7 @@ const mapping = new Map([ ['JVMChaos', 'jvmChaos'], ['K8SChaos', 'k8sChaos'], ['KernelChaos', 'kernelChaos'], + ['MoveAZChaos', 'moveazChaos'], ['NetworkChaos', 'networkChaos'], ['PhysicalMachineChaos', 'physicalmachineChaos'], ['PodChaos', 'podChaos'],