github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/cli/cmd/fault/fault_network.go (about) 1 /* 2 Copyright (C) 2022-2023 ApeCloud Co., Ltd 3 4 This file is part of KubeBlocks project 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU Affero General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU Affero General Public License for more details. 15 16 You should have received a copy of the GNU Affero General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 package fault 21 22 import ( 23 "fmt" 24 25 "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" 26 "github.com/spf13/cobra" 27 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 28 "k8s.io/apimachinery/pkg/runtime" 29 "k8s.io/cli-runtime/pkg/genericiooptions" 30 cmdutil "k8s.io/kubectl/pkg/cmd/util" 31 "k8s.io/kubectl/pkg/util/templates" 32 33 "github.com/1aal/kubeblocks/pkg/cli/create" 34 "github.com/1aal/kubeblocks/pkg/cli/util" 35 ) 36 37 var faultNetWorkExample = templates.Examples(` 38 # Isolate all pods network under the default namespace from the outside world, including the k8s internal network. 39 kbcli fault network partition 40 41 # The specified pod is isolated from the k8s external network "kubeblocks.io". 42 kbcli fault network partition mycluster-mysql-1 --external-targets=kubeblocks.io 43 44 # Isolate the network between two pods. 45 kbcli fault network partition mycluster-mysql-1 --target-label=statefulset.kubernetes.io/pod-name=mycluster-mysql-2 46 47 // Like the partition command, the target can be specified through --target-label or --external-targets. The pod only has obstacles in communicating with this target. If the target is not specified, all communication will be blocked. 48 # Block all pod communication under the default namespace, resulting in a 50% packet loss rate. 49 kbcli fault network loss --loss=50 50 51 # Block the specified pod communication, so that the packet loss rate is 50%. 52 kbcli fault network loss mysql-cluster-mysql-2 --loss=50 53 54 kbcli fault network corrupt --corrupt=50 55 56 # Blocks specified pod communication with a 50% packet corruption rate. 57 kbcli fault network corrupt mysql-cluster-mysql-2 --corrupt=50 58 59 kbcli fault network duplicate --duplicate=50 60 61 # Block specified pod communication so that the packet repetition rate is 50%. 62 kbcli fault network duplicate mysql-cluster-mysql-2 --duplicate=50 63 64 kbcli fault network delay --latency=10s 65 66 # Block the communication of the specified pod, causing its network delay for 10s. 67 kbcli fault network delay mysql-cluster-mysql-2 --latency=10s 68 69 # Limit the communication bandwidth between mysql-cluster-mysql-2 and the outside. 70 kbcli fault network bandwidth mysql-cluster-mysql-2 --rate=1kbps --duration=1m 71 `) 72 73 type Target struct { 74 TargetMode string `json:"mode,omitempty"` 75 TargetValue string `json:"value,omitempty"` 76 TargetSelector `json:"selector,omitempty"` 77 } 78 79 type TargetSelector struct { 80 // Specifies the labels that target Pods come with. 81 TargetLabelSelectors map[string]string `json:"labelSelectors,omitempty"` 82 // Specifies the namespaces to which target Pods belong. 83 TargetNamespaceSelectors []string `json:"namespaces,omitempty"` 84 } 85 86 // NetworkLoss Loss command 87 type NetworkLoss struct { 88 // The percentage of packet loss 89 Loss string `json:"loss,omitempty"` 90 // The correlation of loss or corruption or duplication or delay 91 Correlation string `json:"correlation,omitempty"` 92 } 93 94 // NetworkDelay Delay command 95 type NetworkDelay struct { 96 // The latency of delay 97 Latency string `json:"latency,omitempty"` 98 // The jitter of delay 99 Jitter string `json:"jitter,omitempty"` 100 // The correlation of loss or corruption or duplication or delay 101 Correlation string `json:"correlation,omitempty"` 102 } 103 104 // NetworkDuplicate Duplicate command 105 type NetworkDuplicate struct { 106 // The percentage of packet duplication 107 Duplicate string `json:"duplicate,omitempty"` 108 // The correlation of loss or corruption or duplication or delay 109 Correlation string `json:"correlation,omitempty"` 110 } 111 112 // NetworkCorrupt Corrupt command 113 type NetworkCorrupt struct { 114 // The percentage of packet corruption 115 Corrupt string `json:"corrupt,omitempty"` 116 // The correlation of loss or corruption or duplication or delay 117 Correlation string `json:"correlation,omitempty"` 118 } 119 120 // NetworkBandwidth Bandwidth command 121 type NetworkBandwidth struct { 122 // the rate at which the bandwidth is limited. 123 Rate string `json:"rate,omitempty"` 124 // the number of bytes waiting in the queue. 125 Limit uint32 `json:"limit,omitempty"` 126 // the maximum number of bytes that can be sent instantaneously. 127 Buffer uint32 `json:"buffer,omitempty"` 128 // the bucket's maximum consumption rate. Reference: https://man7.org/linux/man-pages/man8/tc-tbf.8.html. 129 Peakrate uint64 `json:"peakrate,omitempty"` 130 // the size of the peakrate bucket. Reference: https://man7.org/linux/man-pages/man8/tc-tbf.8.html. 131 Minburst uint32 `json:"minburst,omitempty"` 132 } 133 134 type NetworkChaosOptions struct { 135 // Specify the network direction 136 Direction string `json:"direction"` 137 138 // A network target outside of Kubernetes, which can be an IPv4 address or a domain name, 139 // such as "kubeblocks.io". Only works with direction: to. 140 ExternalTargets []string `json:"externalTargets,omitempty"` 141 142 // A collection of target pods. Pods can be selected by namespace and label. 143 Target `json:"target,omitempty"` 144 145 NetworkLoss `json:"loss,omitempty"` 146 147 NetworkDelay `json:"delay,omitempty"` 148 149 NetworkDuplicate `json:"duplicate,omitempty"` 150 151 NetworkCorrupt `json:"corrupt,omitempty"` 152 153 NetworkBandwidth `json:"bandwidth,omitempty"` 154 155 FaultBaseOptions 156 } 157 158 func NewNetworkChaosOptions(f cmdutil.Factory, streams genericiooptions.IOStreams, action string) *NetworkChaosOptions { 159 o := &NetworkChaosOptions{ 160 FaultBaseOptions: FaultBaseOptions{CreateOptions: create.CreateOptions{ 161 Factory: f, 162 IOStreams: streams, 163 CueTemplateName: CueTemplateNetworkChaos, 164 GVR: GetGVR(Group, Version, ResourceNetworkChaos), 165 }, 166 Action: action, 167 }, 168 } 169 o.CreateOptions.PreCreate = o.PreCreate 170 o.CreateOptions.Options = o 171 return o 172 } 173 174 func NewNetworkChaosCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { 175 cmd := &cobra.Command{ 176 Use: "network", 177 Short: "Network chaos.", 178 } 179 cmd.AddCommand( 180 NewPartitionCmd(f, streams), 181 NewLossCmd(f, streams), 182 NewDelayCmd(f, streams), 183 NewDuplicateCmd(f, streams), 184 NewCorruptCmd(f, streams), 185 NewBandwidthCmd(f, streams), 186 NewDNSChaosCmd(f, streams), 187 NewHTTPChaosCmd(f, streams), 188 ) 189 return cmd 190 } 191 192 func NewPartitionCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { 193 o := NewNetworkChaosOptions(f, streams, string(v1alpha1.PartitionAction)) 194 cmd := o.NewCobraCommand(Partition, PartitionShort) 195 196 o.AddCommonFlag(cmd) 197 198 return cmd 199 } 200 201 func NewLossCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { 202 o := NewNetworkChaosOptions(f, streams, string(v1alpha1.LossAction)) 203 cmd := o.NewCobraCommand(Loss, LossShort) 204 205 o.AddCommonFlag(cmd) 206 cmd.Flags().StringVar(&o.Loss, "loss", "", `Indicates the probability of a packet error occurring. Value range: [0, 100].`) 207 cmd.Flags().StringVarP(&o.NetworkLoss.Correlation, "correlation", "c", "", `Indicates the correlation between the probability of a packet error occurring and whether it occurred the previous time. Value range: [0, 100].`) 208 209 util.CheckErr(cmd.MarkFlagRequired("loss")) 210 211 return cmd 212 } 213 214 func NewDelayCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { 215 o := NewNetworkChaosOptions(f, streams, string(v1alpha1.DelayAction)) 216 cmd := o.NewCobraCommand(Delay, DelayShort) 217 218 o.AddCommonFlag(cmd) 219 cmd.Flags().StringVar(&o.Latency, "latency", "", `the length of time to delay.`) 220 cmd.Flags().StringVar(&o.Jitter, "jitter", "", `the variation range of the delay time.`) 221 cmd.Flags().StringVarP(&o.NetworkDelay.Correlation, "correlation", "c", "", `Indicates the probability of a packet error occurring. Value range: [0, 100].`) 222 223 util.CheckErr(cmd.MarkFlagRequired("latency")) 224 225 return cmd 226 } 227 228 func NewDuplicateCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { 229 o := NewNetworkChaosOptions(f, streams, string(v1alpha1.DuplicateAction)) 230 cmd := o.NewCobraCommand(Duplicate, DuplicateShort) 231 232 o.AddCommonFlag(cmd) 233 cmd.Flags().StringVar(&o.Duplicate, "duplicate", "", `the probability of a packet being repeated. Value range: [0, 100].`) 234 cmd.Flags().StringVarP(&o.NetworkDuplicate.Correlation, "correlation", "c", "", `Indicates the correlation between the probability of a packet error occurring and whether it occurred the previous time. Value range: [0, 100].`) 235 236 util.CheckErr(cmd.MarkFlagRequired("duplicate")) 237 238 return cmd 239 } 240 241 func NewCorruptCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { 242 o := NewNetworkChaosOptions(f, streams, string(v1alpha1.CorruptAction)) 243 cmd := o.NewCobraCommand(Corrupt, CorruptShort) 244 245 o.AddCommonFlag(cmd) 246 cmd.Flags().StringVar(&o.Corrupt, "corrupt", "", `Indicates the probability of a packet error occurring. Value range: [0, 100].`) 247 cmd.Flags().StringVarP(&o.NetworkCorrupt.Correlation, "correlation", "c", "", `Indicates the correlation between the probability of a packet error occurring and whether it occurred the previous time. Value range: [0, 100].`) 248 249 util.CheckErr(cmd.MarkFlagRequired("corrupt")) 250 251 return cmd 252 } 253 254 func NewBandwidthCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { 255 o := NewNetworkChaosOptions(f, streams, string(v1alpha1.BandwidthAction)) 256 cmd := o.NewCobraCommand(Bandwidth, BandwidthShort) 257 258 o.AddCommonFlag(cmd) 259 cmd.Flags().StringVar(&o.Rate, "rate", "", `the rate at which the bandwidth is limited. For example : 10 bps/kbps/mbps/gbps.`) 260 cmd.Flags().Uint32Var(&o.Limit, "limit", 1, `the number of bytes waiting in the queue.`) 261 cmd.Flags().Uint32Var(&o.Buffer, "buffer", 1, `the maximum number of bytes that can be sent instantaneously.`) 262 cmd.Flags().Uint64Var(&o.Peakrate, "peakrate", 0, `the maximum consumption rate of the bucket.`) 263 cmd.Flags().Uint32Var(&o.Minburst, "minburst", 0, `the size of the peakrate bucket.`) 264 265 util.CheckErr(cmd.MarkFlagRequired("rate")) 266 267 return cmd 268 } 269 270 func (o *NetworkChaosOptions) NewCobraCommand(use, short string) *cobra.Command { 271 return &cobra.Command{ 272 Use: use, 273 Short: short, 274 Example: faultNetWorkExample, 275 Run: func(cmd *cobra.Command, args []string) { 276 o.Args = args 277 cmdutil.CheckErr(o.CreateOptions.Complete()) 278 cmdutil.CheckErr(o.Validate()) 279 cmdutil.CheckErr(o.Complete()) 280 cmdutil.CheckErr(o.Run()) 281 }, 282 } 283 } 284 285 func (o *NetworkChaosOptions) AddCommonFlag(cmd *cobra.Command) { 286 o.FaultBaseOptions.AddCommonFlag(cmd) 287 288 cmd.Flags().StringVar(&o.Direction, "direction", "to", `You can select "to"" or "from"" or "both"".`) 289 cmd.Flags().StringArrayVarP(&o.ExternalTargets, "external-target", "e", nil, "a network target outside of Kubernetes, which can be an IPv4 address or a domain name,\n\t such as \"www.baidu.com\". Only works with direction: to.") 290 cmd.Flags().StringVar(&o.TargetMode, "target-mode", "", `You can select "one", "all", "fixed", "fixed-percent", "random-max-percent", Specify the experimental mode, that is, which Pods to experiment with.`) 291 cmd.Flags().StringVar(&o.TargetValue, "target-value", "", `If you choose mode=fixed or fixed-percent or random-max-percent, you can enter a value to specify the number or percentage of pods you want to inject.`) 292 cmd.Flags().StringToStringVar(&o.TargetLabelSelectors, "target-label", nil, `label for pod, such as '"app.kubernetes.io/component=mysql, statefulset.kubernetes.io/pod-name=mycluster-mysql-0"'`) 293 cmd.Flags().StringArrayVar(&o.TargetNamespaceSelectors, "target-ns-fault", nil, `Specifies the namespace into which you want to inject faults.`) 294 295 // register flag completion func 296 registerFlagCompletionFunc(cmd, o.Factory) 297 } 298 299 func (o *NetworkChaosOptions) Validate() error { 300 if o.TargetValue == "" && (o.TargetMode == "fixed" || o.TargetMode == "fixed-percent" || o.TargetMode == "random-max-percent") { 301 return fmt.Errorf("--value is required to specify pod nums or percentage") 302 } 303 304 if (o.TargetNamespaceSelectors != nil || o.TargetLabelSelectors != nil) && o.TargetMode == "" { 305 return fmt.Errorf("--target-mode is required to specify a target mode") 306 } 307 308 if o.ExternalTargets != nil && o.Direction != "to" { 309 return fmt.Errorf("--direction=to is required when specifying external targets") 310 } 311 312 if ok, err := IsInteger(o.TargetValue); !ok { 313 return err 314 } 315 316 if ok, err := IsInteger(o.Loss); !ok { 317 return err 318 } 319 320 if ok, err := IsInteger(o.Corrupt); !ok { 321 return err 322 } 323 324 if ok, err := IsInteger(o.Duplicate); !ok { 325 return err 326 } 327 328 if ok, err := IsRegularMatch(o.Latency); !ok { 329 return err 330 } 331 332 if ok, err := IsRegularMatch(o.Jitter); !ok { 333 return err 334 } 335 336 return o.BaseValidate() 337 } 338 339 func (o *NetworkChaosOptions) Complete() error { 340 return o.BaseComplete() 341 } 342 343 func (o *NetworkChaosOptions) PreCreate(obj *unstructured.Unstructured) error { 344 c := &v1alpha1.NetworkChaos{} 345 if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, c); err != nil { 346 return err 347 } 348 349 data, e := runtime.DefaultUnstructuredConverter.ToUnstructured(c) 350 if e != nil { 351 return e 352 } 353 obj.SetUnstructuredContent(data) 354 return nil 355 }