shardingsphere-operator/pkg/kubernetes/chaosmesh/builder.go (544 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package chaosmesh import ( "context" "errors" "strconv" "github.com/apache/shardingsphere-on-cloud/shardingsphere-operator/api/v1alpha1" chaosmeshv1alpha1 "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) const ( AnnoPodSelectorMode = "selector.chaos-mesh.org/mode" AnnoPodSelectorValue = "selector.chaos-mesh.org/value" AnnoTargetPodSelectorMode = "target-selector.chaos-mesh.org/mode" AnnoTargetPodSelectorValue = "target-selector.chaos-mesh.org/value" AnnoStressTime = "stresschaos.chaos-mesh.org/time" AnnoStressOOMScoreAdj = "stresschaos.chaos-mesh.org/oomScoreAdj" AnnoNetworkAction = "networkchaos.chaos-mesh.org/action" AnnoNetworkDevice = "networkchaos.chaos-mesh.org/device" AnnoNetworkTargetDevice = "networkchaos.chaos-mesh.org/targetDevice" AnnoNetworkBandwidthRate = "networkchaos.chaos-mesh.org/bandwidth:rate" AnnoNetworkBandwidthLimit = "networkchaos.chaos-mesh.org/bandwidth:limit" AnnoNetworkBandwidthBuffer = "networkchaos.chaos-mesh.org/bandwidth:buffer" AnnoNetworkBandwidthPeakrate = "networkchaos.chaos-mesh.org/bandwidth:peakrate" AnnoNetworkBandwidthMinBurst = "networkchaos.chaos-mesh.org/bandwidth:minburst" ) var ( ErrConvert = errors.New("can not convert chaos interface to specify struct") ErrNotChanged = errors.New("object not changed") ErrChangedSpec = errors.New("change spec") ) type GenericChaos interface{} func getStatus(ssChaos *v1alpha1.Chaos, chaos GenericChaos) *chaosmeshv1alpha1.ChaosStatus { var status *chaosmeshv1alpha1.ChaosStatus if ssChaos.Spec.EmbedChaos.PodChaos != nil { if podChao, ok := chaos.(*chaosmeshv1alpha1.PodChaos); ok && podChao != nil { status = podChao.GetStatus() } else if ssChao, ok := chaos.(*chaosmeshv1alpha1.StressChaos); ok && ssChao != nil { status = ssChao.GetStatus() } } if ssChaos.Spec.EmbedChaos.NetworkChaos != nil { if networkChaos, ok := chaos.(*chaosmeshv1alpha1.NetworkChaos); ok && networkChaos != nil { status = networkChaos.GetStatus() } } return status } func ConvertChaosStatus(ctx context.Context, ssChaos *v1alpha1.Chaos, chaos GenericChaos) v1alpha1.ChaosCondition { status := getStatus(ssChaos, chaos) if status == nil { return v1alpha1.Unknown } var conditions = map[chaosmeshv1alpha1.ChaosConditionType]bool{} for i := range status.Conditions { conditions[status.Conditions[i].Type] = status.Conditions[i].Status == corev1.ConditionTrue } return judgeCondition(conditions, status.Experiment.DesiredPhase) } func judgeCondition(condition map[chaosmeshv1alpha1.ChaosConditionType]bool, phase chaosmeshv1alpha1.DesiredPhase) v1alpha1.ChaosCondition { if condition[chaosmeshv1alpha1.ConditionPaused] { if !condition[chaosmeshv1alpha1.ConditionSelected] { return v1alpha1.NoTarget } return v1alpha1.Paused } if condition[chaosmeshv1alpha1.ConditionSelected] { if condition[chaosmeshv1alpha1.ConditionAllRecovered] && phase == chaosmeshv1alpha1.StoppedPhase { return v1alpha1.AllRecovered } if condition[chaosmeshv1alpha1.ConditionAllInjected] && phase == chaosmeshv1alpha1.RunningPhase { return v1alpha1.AllInjected } } return v1alpha1.Unknown } func NewPodChaos(ssChao *v1alpha1.Chaos) (PodChaos, error) { chao := ssChao.Spec.PodChaos pcb := NewPodChaosBuilder() pcb.SetName(ssChao.Name).SetNamespace(ssChao.Namespace).SetLabels(ssChao.Labels) pcb.SetAction(string(chao.Action)) containerSelector := &chaosmeshv1alpha1.ContainerSelector{} psb := NewPodSelectorBuilder() psb.SetSelectMode(ssChao.Annotations[AnnoPodSelectorMode]). SetValue(ssChao.Annotations[AnnoPodSelectorValue]). SetNodes(chao.Nodes). SetPods(chao.Pods). SetNodeSelector(chao.NodeSelectors). // SetPodPhaseSelectors(chao.Pods). SetNamespaces(chao.Namespaces). // SetFieldSelector(). SetLabelSelector(chao.LabelSelectors). SetExpressionSelectors(chao.ExpressionSelectors). SetAnnotationSelectors(chao.AnnotationSelectors) podSelector := *psb.Build() containerSelector.PodSelector = podSelector switch chao.Action { case v1alpha1.PodKill: gp := ssChao.Spec.EmbedChaos.PodChaos.Params.PodKill.GracePeriod pcb.SetGracePeriod(gp) case v1alpha1.PodFailure: pcb.SetDuration(chao.Params.PodFailure.Duration) case v1alpha1.ContainerKill: containerSelector.ContainerNames = ssChao.Spec.EmbedChaos.PodChaos.Params.ContainerKill.ContainerNames } pcb.SetContainerSelector(containerSelector) podChao := pcb.Build() return podChao, nil } func NewStressChaos(chaos *v1alpha1.Chaos) (StressChaos, error) { sc := &chaosmeshv1alpha1.StressChaos{} sc.Namespace = chaos.Namespace sc.Name = chaos.Name sc.Labels = chaos.Labels chao := chaos.Spec.PodChaos psb := NewPodSelectorBuilder() psb.SetNamespaces(chao.Namespaces). SetExpressionSelectors(chao.ExpressionSelectors). SetNodes(chao.Nodes). SetNodeSelector(chao.NodeSelectors). SetAnnotationSelectors(chao.AnnotationSelectors). SetLabelSelector(chao.LabelSelectors). SetPods(chao.Pods) psb.SetSelectMode(chaos.Annotations[AnnoPodSelectorMode]). SetValue(chaos.Annotations[AnnoPodSelectorValue]) sc.Spec.ContainerSelector = chaosmeshv1alpha1.ContainerSelector{ PodSelector: *psb.Build(), } if chao.Action == v1alpha1.CPUStress { setCPUStressParams(chaos, sc) } if chao.Action == v1alpha1.MemoryStress { if err := setMemoryStressParams(chaos, sc); err != nil { return nil, err } } return sc, nil } func setCPUStressParams(sschaos *v1alpha1.Chaos, chaos *chaosmeshv1alpha1.StressChaos) { cpu := &chaosmeshv1alpha1.CPUStressor{ Stressor: chaosmeshv1alpha1.Stressor{ Workers: sschaos.Spec.PodChaos.Params.CPUStress.Cores, }, Load: &sschaos.Spec.PodChaos.Params.CPUStress.Load, } chaos.Spec.Stressors = &chaosmeshv1alpha1.Stressors{ CPUStressor: cpu, } chaos.Spec.Duration = &sschaos.Spec.PodChaos.Params.CPUStress.Duration } func setMemoryStressParams(sschaos *v1alpha1.Chaos, chaos *chaosmeshv1alpha1.StressChaos) error { var ( oom int err error ) if adj, ok := sschaos.Annotations[AnnoStressOOMScoreAdj]; ok { oom, err = strconv.Atoi(adj) if err != nil { return err } } memory := &chaosmeshv1alpha1.MemoryStressor{ Stressor: chaosmeshv1alpha1.Stressor{ Workers: sschaos.Spec.PodChaos.Params.MemoryStress.Workers, }, Size: sschaos.Spec.PodChaos.Params.MemoryStress.Consumption, OOMScoreAdj: oom, Options: []string{ sschaos.Annotations[AnnoStressTime], }, } chaos.Spec.Stressors = &chaosmeshv1alpha1.Stressors{ MemoryStressor: memory, } chaos.Spec.Duration = &sschaos.Spec.PodChaos.Params.MemoryStress.Duration return err } func getAnnotation(anno map[string]string, k string) string { if v, ok := anno[k]; ok { return v } return "" } func NewNetworkChaos(ssChao *v1alpha1.Chaos) (NetworkChaos, error) { chao := ssChao.Spec.NetworkChaos ncb := NewNetworkChaosBuilder() ncb.SetName(ssChao.Name).SetNamespace(ssChao.Namespace).SetLabels(ssChao.Labels). SetAction(string(chao.Action)). SetDuration(chao.Duration). SetDirection(string(chao.Direction)) tcParams := &chaosmeshv1alpha1.TcParameter{} switch chao.Action { case v1alpha1.Delay: tcParams.Delay = &chaosmeshv1alpha1.DelaySpec{ Latency: chao.Params.Delay.Latency, Jitter: chao.Params.Delay.Jitter, } case v1alpha1.Corruption: tcParams.Corrupt = &chaosmeshv1alpha1.CorruptSpec{ Corrupt: chao.Params.Corruption.Corruption, } case v1alpha1.Duplication: tcParams.Duplicate = &chaosmeshv1alpha1.DuplicateSpec{ Duplicate: chao.Params.Duplication.Duplication, } case v1alpha1.Loss: tcParams.Loss = &chaosmeshv1alpha1.LossSpec{ Loss: chao.Params.Loss.Loss, } case v1alpha1.Bandwidth: bwab := NewBandWidthActionBuilder() bwab.SetRate(getAnnotation(ssChao.Annotations, AnnoNetworkBandwidthRate)) bwab.SetLimit(getAnnotation(ssChao.Annotations, AnnoNetworkBandwidthLimit)) bwab.SetBuffer(getAnnotation(ssChao.Annotations, AnnoNetworkBandwidthBuffer)) bwab.SetPeakRate(getAnnotation(ssChao.Annotations, AnnoNetworkBandwidthPeakrate)) bwab.SetMinBurst(getAnnotation(ssChao.Annotations, AnnoNetworkBandwidthMinBurst)) tcParams.Bandwidth = bwab.Build() case v1alpha1.Partition: } psb := NewPodSelectorBuilder() psb.SetNamespaces(chao.Source.Namespaces). SetExpressionSelectors(chao.Source.ExpressionSelectors). SetNodes(chao.Source.Nodes). SetNodeSelector(chao.Source.NodeSelectors). SetAnnotationSelectors(chao.Source.AnnotationSelectors). SetLabelSelector(chao.Source.LabelSelectors). SetPods(chao.Source.Pods) psb.SetSelectMode(ssChao.Annotations[AnnoPodSelectorMode]). SetValue(ssChao.Annotations[AnnoPodSelectorValue]) ncb.SetPodSelector(psb.Build()) tpsb := NewPodSelectorBuilder() tpsb.SetNamespaces(chao.Target.Namespaces). SetExpressionSelectors(chao.Target.ExpressionSelectors). SetNodes(chao.Target.Nodes). SetNodeSelector(chao.Target.NodeSelectors). SetAnnotationSelectors(chao.Target.AnnotationSelectors). SetLabelSelector(chao.Target.LabelSelectors). SetPods(chao.Target.Pods). SetSelectMode(ssChao.Annotations[AnnoTargetPodSelectorMode]). SetValue(ssChao.Annotations[AnnoTargetPodSelectorValue]) ncb.SetTarget(tpsb.Build()). SetDevice(ssChao.Annotations[AnnoNetworkDevice]). SetTargetDevice(ssChao.Annotations[AnnoNetworkTargetDevice]). SetTcParameter(*tcParams) networkChao := ncb.Build() return networkChao, nil } type BandWidthActionBuilder interface { SetRate(string) BandWidthActionBuilder SetLimit(string) BandWidthActionBuilder SetBuffer(string) BandWidthActionBuilder SetPeakRate(string) BandWidthActionBuilder SetMinBurst(string) BandWidthActionBuilder Build() *chaosmeshv1alpha1.BandwidthSpec } func NewBandWidthActionBuilder() BandWidthActionBuilder { return &bandWidthActionBuilder{ bandwidth: &chaosmeshv1alpha1.BandwidthSpec{}, } } type bandWidthActionBuilder struct { bandwidth *chaosmeshv1alpha1.BandwidthSpec } func (b *bandWidthActionBuilder) SetRate(s string) BandWidthActionBuilder { b.bandwidth.Rate = s return b } func (b *bandWidthActionBuilder) SetLimit(s string) BandWidthActionBuilder { lim, err := strconv.ParseInt(s, 10, 32) if err == nil { b.bandwidth.Limit = uint32(lim) } return b } func (b *bandWidthActionBuilder) SetBuffer(s string) BandWidthActionBuilder { buf, err := strconv.ParseInt(s, 10, 32) if err == nil { b.bandwidth.Buffer = uint32(buf) } return b } func (b *bandWidthActionBuilder) SetPeakRate(s string) BandWidthActionBuilder { pr, err := strconv.ParseInt(s, 10, 64) if err == nil { ret := uint64(pr) b.bandwidth.Peakrate = &ret } return b } func (b *bandWidthActionBuilder) SetMinBurst(s string) BandWidthActionBuilder { burst, err := strconv.ParseInt(s, 10, 32) if err == nil { ret := uint32(burst) b.bandwidth.Minburst = &ret } return b } func (b *bandWidthActionBuilder) Build() *chaosmeshv1alpha1.BandwidthSpec { return b.bandwidth } type PodChaosBuilder interface { SetName(string) PodChaosBuilder SetNamespace(string) PodChaosBuilder SetLabels(map[string]string) PodChaosBuilder SetAnnotations(map[string]string) PodChaosBuilder SetContainerSelector(*chaosmeshv1alpha1.ContainerSelector) PodChaosBuilder SetAction(string) PodChaosBuilder SetDuration(*string) PodChaosBuilder SetGracePeriod(int64) PodChaosBuilder Build() *chaosmeshv1alpha1.PodChaos } func NewPodChaosBuilder() PodChaosBuilder { return &podChaosBuilder{ podChaos: DefaultPodChaos(), } } type podChaosBuilder struct { podChaos *chaosmeshv1alpha1.PodChaos } func (p *podChaosBuilder) SetNamespace(namespace string) PodChaosBuilder { p.podChaos.Namespace = namespace return p } func (p *podChaosBuilder) SetName(name string) PodChaosBuilder { p.podChaos.Name = name return p } func (p *podChaosBuilder) SetLabels(labels map[string]string) PodChaosBuilder { p.podChaos.Labels = labels return p } func (p *podChaosBuilder) SetAnnotations(annotations map[string]string) PodChaosBuilder { p.podChaos.Annotations = annotations return p } func (p *podChaosBuilder) SetContainerSelector(selector *chaosmeshv1alpha1.ContainerSelector) PodChaosBuilder { p.podChaos.Spec.ContainerSelector = *selector return p } func (p *podChaosBuilder) SetAction(action string) PodChaosBuilder { if v1alpha1.PodChaosAction(action) == v1alpha1.PodFailure { p.podChaos.Spec.Action = chaosmeshv1alpha1.PodFailureAction } if v1alpha1.PodChaosAction(action) == v1alpha1.ContainerKill { p.podChaos.Spec.Action = chaosmeshv1alpha1.ContainerKillAction } if chaosmeshv1alpha1.PodChaosAction(action) == chaosmeshv1alpha1.PodKillAction { p.podChaos.Spec.Action = chaosmeshv1alpha1.PodKillAction } return p } func (p *podChaosBuilder) SetDuration(duration *string) PodChaosBuilder { p.podChaos.Spec.Duration = duration return p } func (p *podChaosBuilder) SetGracePeriod(gracePeriod int64) PodChaosBuilder { p.podChaos.Spec.GracePeriod = gracePeriod return p } func (p *podChaosBuilder) Build() *chaosmeshv1alpha1.PodChaos { return p.podChaos } type NetworkChaosBuilder interface { SetNamespace(string) NetworkChaosBuilder SetName(string) NetworkChaosBuilder SetLabels(map[string]string) NetworkChaosBuilder SetAnnotations(map[string]string) NetworkChaosBuilder SetPodSelector(*chaosmeshv1alpha1.PodSelector) NetworkChaosBuilder SetAction(string) NetworkChaosBuilder SetDevice(string) NetworkChaosBuilder SetDuration(*string) NetworkChaosBuilder SetDirection(string) NetworkChaosBuilder SetTarget(*chaosmeshv1alpha1.PodSelector) NetworkChaosBuilder SetTargetDevice(string) NetworkChaosBuilder SetTcParameter(chaosmeshv1alpha1.TcParameter) NetworkChaosBuilder Build() *chaosmeshv1alpha1.NetworkChaos } type netWorkChaosBuilder struct { netWorkChaos *chaosmeshv1alpha1.NetworkChaos } func (n *netWorkChaosBuilder) SetNamespace(namespace string) NetworkChaosBuilder { n.netWorkChaos.Namespace = namespace return n } func (n *netWorkChaosBuilder) SetName(name string) NetworkChaosBuilder { n.netWorkChaos.Name = name return n } func (n *netWorkChaosBuilder) SetLabels(labels map[string]string) NetworkChaosBuilder { n.netWorkChaos.Labels = labels return n } func (n *netWorkChaosBuilder) SetAnnotations(annotations map[string]string) NetworkChaosBuilder { n.netWorkChaos.Annotations = annotations return n } func (n *netWorkChaosBuilder) SetPodSelector(selector *chaosmeshv1alpha1.PodSelector) NetworkChaosBuilder { n.netWorkChaos.Spec.PodSelector = *selector return n } func (n *netWorkChaosBuilder) SetAction(action string) NetworkChaosBuilder { if chaosmeshv1alpha1.NetworkChaosAction(action) == chaosmeshv1alpha1.BandwidthAction { n.netWorkChaos.Spec.Action = chaosmeshv1alpha1.BandwidthAction } if v1alpha1.NetworkChaosAction(action) == v1alpha1.Corruption { n.netWorkChaos.Spec.Action = chaosmeshv1alpha1.CorruptAction } if v1alpha1.NetworkChaosAction(action) == v1alpha1.Partition { n.netWorkChaos.Spec.Action = chaosmeshv1alpha1.PartitionAction } if v1alpha1.NetworkChaosAction(action) == v1alpha1.Loss { n.netWorkChaos.Spec.Action = chaosmeshv1alpha1.LossAction } if v1alpha1.NetworkChaosAction(action) == v1alpha1.Duplication { n.netWorkChaos.Spec.Action = chaosmeshv1alpha1.DuplicateAction } return n } func (n *netWorkChaosBuilder) SetDevice(device string) NetworkChaosBuilder { n.netWorkChaos.Spec.Device = device return n } func (n *netWorkChaosBuilder) SetDuration(duration *string) NetworkChaosBuilder { n.netWorkChaos.Spec.Duration = duration return n } func (n *netWorkChaosBuilder) SetDirection(direction string) NetworkChaosBuilder { n.netWorkChaos.Spec.Direction = chaosmeshv1alpha1.Direction(direction) return n } func (n *netWorkChaosBuilder) SetTarget(selector *chaosmeshv1alpha1.PodSelector) NetworkChaosBuilder { n.netWorkChaos.Spec.Target = selector return n } func (n *netWorkChaosBuilder) SetTargetDevice(targetDevice string) NetworkChaosBuilder { n.netWorkChaos.Spec.TargetDevice = targetDevice return n } func (n *netWorkChaosBuilder) SetTcParameter(parameter chaosmeshv1alpha1.TcParameter) NetworkChaosBuilder { n.netWorkChaos.Spec.TcParameter = parameter return n } func (n *netWorkChaosBuilder) Build() *chaosmeshv1alpha1.NetworkChaos { return n.netWorkChaos } func NewNetworkChaosBuilder() NetworkChaosBuilder { return &netWorkChaosBuilder{ netWorkChaos: DefaultNetworkChaos(), } } type PodSelectorBuilder interface { // PodSelector SetSelectMode(string) PodSelectorBuilder SetValue(string) PodSelectorBuilder // PodSelectorSpec SetNodes([]string) PodSelectorBuilder SetPods(map[string][]string) PodSelectorBuilder SetNodeSelector(map[string]string) PodSelectorBuilder SetPodPhaseSelectors([]string) PodSelectorBuilder // GenericSelectorSpec SetNamespaces([]string) PodSelectorBuilder SetFieldSelectors(map[string]string) PodSelectorBuilder SetLabelSelector(map[string]string) PodSelectorBuilder SetExpressionSelectors([]metav1.LabelSelectorRequirement) PodSelectorBuilder SetAnnotationSelectors(map[string]string) PodSelectorBuilder Build() *chaosmeshv1alpha1.PodSelector } func NewPodSelectorBuilder() PodSelectorBuilder { return &podSelectorBuilder{ podSelector: &chaosmeshv1alpha1.PodSelector{}, } } type podSelectorBuilder struct { podSelector *chaosmeshv1alpha1.PodSelector } func (p *podSelectorBuilder) SetNamespaces(namespaces []string) PodSelectorBuilder { p.podSelector.Selector.Namespaces = namespaces return p } func (p *podSelectorBuilder) SetSelectMode(mode string) PodSelectorBuilder { p.podSelector.Mode = chaosmeshv1alpha1.SelectorMode(mode) return p } func (p *podSelectorBuilder) SetValue(value string) PodSelectorBuilder { p.podSelector.Value = value return p } func (p *podSelectorBuilder) SetNodes(nodes []string) PodSelectorBuilder { p.podSelector.Selector.Nodes = nodes return p } func (p *podSelectorBuilder) SetPods(pods map[string][]string) PodSelectorBuilder { p.podSelector.Selector.Pods = pods return p } func (p *podSelectorBuilder) SetNodeSelector(nodeSelector map[string]string) PodSelectorBuilder { p.podSelector.Selector.NodeSelectors = nodeSelector return p } func (p *podSelectorBuilder) SetPodPhaseSelectors(podPhaseSelectors []string) PodSelectorBuilder { p.podSelector.Selector.PodPhaseSelectors = podPhaseSelectors return p } func (p *podSelectorBuilder) SetFieldSelectors(fieldSelectors map[string]string) PodSelectorBuilder { p.podSelector.Selector.FieldSelectors = fieldSelectors return p } func (p *podSelectorBuilder) SetLabelSelector(labelSelectors map[string]string) PodSelectorBuilder { p.podSelector.Selector.LabelSelectors = labelSelectors return p } func (p *podSelectorBuilder) SetExpressionSelectors(requirements []metav1.LabelSelectorRequirement) PodSelectorBuilder { p.podSelector.Selector.ExpressionSelectors = requirements return p } func (p *podSelectorBuilder) SetAnnotationSelectors(annotationSelectors map[string]string) PodSelectorBuilder { p.podSelector.Selector.AnnotationSelectors = annotationSelectors return p } func (p *podSelectorBuilder) Build() *chaosmeshv1alpha1.PodSelector { return p.podSelector } func DefaultPodChaos() *chaosmeshv1alpha1.PodChaos { d := "1m" return &chaosmeshv1alpha1.PodChaos{ ObjectMeta: metav1.ObjectMeta{ Name: "shardingsphere-proxy", Namespace: "default", Labels: map[string]string{}, }, Spec: chaosmeshv1alpha1.PodChaosSpec{ Action: chaosmeshv1alpha1.ContainerKillAction, Duration: &d, }, } } func DefaultNetworkChaos() *chaosmeshv1alpha1.NetworkChaos { return &chaosmeshv1alpha1.NetworkChaos{ ObjectMeta: metav1.ObjectMeta{ Name: "shardingsphere-proxy", Namespace: "default", Labels: map[string]string{}, }, Spec: chaosmeshv1alpha1.NetworkChaosSpec{ Action: chaosmeshv1alpha1.PartitionAction, Direction: "to", }, } }