From 90ae5949c0d68404ed46e7fd473908b994215a16 Mon Sep 17 00:00:00 2001 From: caimingxia Date: Thu, 25 Nov 2021 15:20:32 +0800 Subject: [PATCH] support cri command --- exec/container/container.go | 4 +- exec/container/controller.go | 44 +++++++++++------- exec/model/context.go | 27 +++++++---- exec/model/executor.go | 88 ++++++++++++++++++++++++++++++++++-- exec/model/filter.go | 2 +- exec/model/model.go | 11 ++++- version/version.go | 33 +++++++++++++- 7 files changed, 175 insertions(+), 34 deletions(-) diff --git a/exec/container/container.go b/exec/container/container.go index 9172b4e..7dbfe74 100644 --- a/exec/container/container.go +++ b/exec/container/container.go @@ -18,7 +18,7 @@ package container import ( "fmt" - dockerexec "github.com/chaosblade-io/chaosblade-exec-docker/exec" + criexec "github.com/chaosblade-io/chaosblade-exec-cri/exec" "github.com/chaosblade-io/chaosblade-exec-os/exec" "github.com/chaosblade-io/chaosblade-spec-go/spec" "strings" @@ -38,7 +38,7 @@ func NewResourceModelSpec(client *channel.Client) model.ResourceExpModelSpec { } osSubExpModelSpecs := model.NewOSSubResourceModelSpec().ExpModels() - containerSelfModelSpec := dockerexec.NewContainerCommandSpec() + containerSelfModelSpec := criexec.NewContainerCommandSpec() javaExpModelSpecs := getJvmModels() subExpModelCommandSpecs := make([]spec.ExpModelCommandSpec, 0) diff --git a/exec/container/controller.go b/exec/container/controller.go index dddce41..0e9983b 100644 --- a/exec/container/controller.go +++ b/exec/container/controller.go @@ -22,6 +22,7 @@ import ( "strconv" "strings" + "github.com/chaosblade-io/chaosblade-exec-cri/exec/container" "github.com/chaosblade-io/chaosblade-spec-go/util" "github.com/sirupsen/logrus" "k8s.io/api/core/v1" @@ -134,8 +135,11 @@ func getMatchedContainerMetaList(pods []v1.Pod, containerIdsValue, containerName continue } for _, containerStatus := range containerStatuses { - containerId := model.TruncateContainerObjectMetaUid(containerStatus.ContainerID) + containerRuntime,containerId := model.TruncateContainerObjectMetaUid(containerStatus.ContainerID) containerName := containerStatus.Name + if containerRuntime == container.DockerRuntime { + containerId = containerId[:12] + } if containerIdsValue != "" { for _, expectedContainerId := range expectedContainerIds { if expectedContainerId == "" { @@ -143,11 +147,12 @@ func getMatchedContainerMetaList(pods []v1.Pod, containerIdsValue, containerName } if strings.HasPrefix(containerId, expectedContainerId) { containerObjectMetaList = append(containerObjectMetaList, model.ContainerObjectMeta{ - ContainerId: containerId[:12], - ContainerName: containerName, - PodName: pod.Name, - Namespace: pod.Namespace, - NodeName: pod.Spec.NodeName, + ContainerRuntime: containerRuntime, + ContainerId: containerId, + ContainerName: containerName, + PodName: pod.Name, + Namespace: pod.Namespace, + NodeName: pod.Spec.NodeName, }) } } @@ -159,11 +164,12 @@ func getMatchedContainerMetaList(pods []v1.Pod, containerIdsValue, containerName if expectedName == containerName { // matched containerObjectMetaList = append(containerObjectMetaList, model.ContainerObjectMeta{ - ContainerId: containerId[:12], - ContainerName: containerName, - PodName: pod.Name, - Namespace: pod.Namespace, - NodeName: pod.Spec.NodeName, + ContainerRuntime: containerRuntime, + ContainerId: containerId, + ContainerName: containerName, + PodName: pod.Name, + Namespace: pod.Namespace, + NodeName: pod.Spec.NodeName, }) } } @@ -179,13 +185,17 @@ func getMatchedContainerMetaList(pods []v1.Pod, containerIdsValue, containerName return containerObjectMetaList, spec.ResponseFailWithFlags(spec.ParameterIllegal, model.ContainerIndexFlag.Name, containerIndexValue, "out of bound") } - containerId := model.TruncateContainerObjectMetaUid(containerStatuses[idx].ContainerID) + containerRuntime, containerId := model.TruncateContainerObjectMetaUid(containerStatuses[idx].ContainerID) + if containerRuntime == container.DockerRuntime { + containerId = containerId[:12] + } containerObjectMetaList = append(containerObjectMetaList, model.ContainerObjectMeta{ - ContainerId: containerId[:12], - ContainerName: containerStatuses[idx].Name, - PodName: pod.Name, - Namespace: pod.Namespace, - NodeName: pod.Spec.NodeName, + ContainerRuntime: containerRuntime, + ContainerId: containerId, + ContainerName: containerStatuses[idx].Name, + PodName: pod.Name, + Namespace: pod.Namespace, + NodeName: pod.Spec.NodeName, }) } } diff --git a/exec/model/context.go b/exec/model/context.go index ccad202..370e776 100644 --- a/exec/model/context.go +++ b/exec/model/context.go @@ -29,12 +29,13 @@ const ExperimentIdKey = "ExperimentIdKey" type ContainerObjectMeta struct { // experiment id - Id string - ContainerId string - ContainerName string - PodName string - NodeName string - Namespace string + Id string + ContainerRuntime string + ContainerId string + ContainerName string + PodName string + NodeName string + Namespace string } type ContainerMatchedList []ContainerObjectMeta @@ -77,12 +78,15 @@ func (c *ContainerObjectMeta) GetIdentifier() string { if c.ContainerId != "" { identifier = fmt.Sprintf("%s/%s", identifier, c.ContainerId) } + if c.ContainerRuntime != "" { + identifier = fmt.Sprintf("%s/%s", identifier, c.ContainerRuntime) + } return identifier } -// Namespace/Node/Pod/ContainerName/ContainerId(12 length) +// Namespace/Node/Pod/ContainerName/ContainerId/containerRuntime func ParseIdentifier(identifier string) ContainerObjectMeta { - ss := strings.SplitN(identifier, "/", 5) + ss := strings.SplitN(identifier, "/", 6) meta := ContainerObjectMeta{} switch len(ss) { case 0: @@ -107,6 +111,13 @@ func ParseIdentifier(identifier string) ContainerObjectMeta { meta.PodName = ss[2] meta.ContainerName = ss[3] meta.ContainerId = ss[4] + case 6: + meta.Namespace = ss[0] + meta.NodeName = ss[1] + meta.PodName = ss[2] + meta.ContainerName = ss[3] + meta.ContainerId = ss[4] + meta.ContainerRuntime = ss[5] } return meta } diff --git a/exec/model/executor.go b/exec/model/executor.go index aa273ce..12e50d5 100644 --- a/exec/model/executor.go +++ b/exec/model/executor.go @@ -27,6 +27,7 @@ import ( "sync" "time" + "github.com/chaosblade-io/chaosblade-exec-cri/exec/container" "github.com/chaosblade-io/chaosblade-exec-docker/exec" "github.com/chaosblade-io/chaosblade-spec-go/util" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -42,6 +43,7 @@ import ( "github.com/chaosblade-io/chaosblade-operator/channel" "github.com/chaosblade-io/chaosblade-operator/pkg/apis/chaosblade/v1alpha1" "github.com/chaosblade-io/chaosblade-operator/pkg/runtime/chaosblade" + "github.com/chaosblade-io/chaosblade-operator/version" ) type ExperimentIdentifierInPod struct { @@ -83,13 +85,17 @@ func (e *ExecCommandInPodExecutor) getExperimentIdentifiers(ctx context.Context, _, destroy := spec.IsDestroy(ctx) isDockerNetwork := expModel.ActionFlags[IsDockerNetworkFlag.Name] == "true" + UseSidecarContainerNetwork := expModel.ActionFlags[UseSidecarContainerNetworkFlag.Name] == "true" isContainerSelfTarget := expModel.Target == "container" isContainerNetworkTarget := expModel.Target == "network" isNodeScope := expModel.Scope == "node" if isNodeScope { return e.getNodeExperimentIdentifiers(experimentId, expModel, containerObjectMetaList, matchers, destroy) } - if isContainerSelfTarget || (isContainerNetworkTarget && isDockerNetwork) { + if isContainerSelfTarget || (isContainerNetworkTarget && (isDockerNetwork || UseSidecarContainerNetwork)) { + if version.CheckVerisonHaveCriCommand() || containerObjectMetaList[0].ContainerRuntime == container.ContainerdRuntime { + return e.getCriExperimentIdentifiers(experimentId, expModel, containerObjectMetaList, matchers, destroy, isContainerNetworkTarget) + } return e.getDockerExperimentIdentifiers(experimentId, expModel, containerObjectMetaList, matchers, destroy, isContainerNetworkTarget) } if destroy { @@ -461,7 +467,7 @@ func (e *ExecCommandInPodExecutor) getNewContainerIdByPod(podName, podNamespace, } for _, containerStatus := range containerStatuses { if containerName == containerStatus.Name { - containerLongId := TruncateContainerObjectMetaUid(containerStatus.ContainerID) + _,containerLongId := TruncateContainerObjectMetaUid(containerStatus.ContainerID) if len(containerLongId) > 12 { return containerLongId[:12], nil } @@ -483,6 +489,18 @@ func (e *ExecCommandInPodExecutor) getDockerExperimentIdentifiers(experimentId s return e.generateCreateDockerCommands(experimentId, expModel, containerObjectMetaList, matchers) } +func (e *ExecCommandInPodExecutor) getCriExperimentIdentifiers(experimentId string, expModel *spec.ExpModel, +containerObjectMetaList ContainerMatchedList, matchers string, destroy, isNetworkTarget bool) ([]ExperimentIdentifierInPod, error) { + if isNetworkTarget { + matchers = fmt.Sprintf("%s --image-repo %s --image-version %s", + matchers, chaosblade.Constant.ImageRepoFunc(), chaosblade.Version) + } + if destroy { + return e.generateDestroyCriCommands(experimentId, expModel, containerObjectMetaList, matchers, isNetworkTarget) + } + return e.generateCreateCriCommands(experimentId, expModel, containerObjectMetaList, matchers) +} + // GetChaosBladeDaemonsetPodName func (e *ExecCommandInPodExecutor) GetChaosBladeDaemonsetPodName(nodeName string) (string, error) { podName := chaosblade.DaemonsetPodNames[nodeName] @@ -587,6 +605,64 @@ func (e *ExecCommandInPodExecutor) generateCreateDockerCommands(experimentId str return identifiers, nil } +func (e *ExecCommandInPodExecutor) generateDestroyCriCommands(experimentId string, expModel *spec.ExpModel, + containerObjectMetaList ContainerMatchedList, matchers string, isNetworkTarget bool) ([]ExperimentIdentifierInPod, error) { + command := fmt.Sprintf("%s destroy cri %s %s %s", getTargetChaosBladeBin(expModel), expModel.Target, expModel.ActionName, matchers) + identifiers := make([]ExperimentIdentifierInPod, 0) + for idx, obj := range containerObjectMetaList { + daemonsetPodName, err := e.GetChaosBladeDaemonsetPodName(obj.NodeName) + if err != nil { + logrus.WithField("experiment", experimentId). + Errorf("get chaosblade tool pod for destroying failed on %s node, %v", obj.NodeName, err) + return identifiers, err + } + generatedCommand := command + if isNetworkTarget { + generatedCommand = fmt.Sprintf("%s --container-id %s --container-runtime %s", generatedCommand, obj.ContainerId, obj.ContainerRuntime) + } else { + if obj.Id != "" { + generatedCommand = fmt.Sprintf("%s --uid %s", command, obj.Id) + } + generatedCommand = fmt.Sprintf("%s --container-name %s --container-runtime %s", generatedCommand, obj.ContainerName, obj.ContainerRuntime) + } + identifierInPod := ExperimentIdentifierInPod{ + ContainerObjectMeta: containerObjectMetaList[idx], + Command: generatedCommand, + ChaosBladeContainerName: chaosblade.DaemonsetPodName, + ChaosBladeNamespace: chaosblade.DaemonsetPodNamespace, + ChaosBladePodName: daemonsetPodName, + } + identifiers = append(identifiers, identifierInPod) + } + return identifiers, nil +} + +func (e *ExecCommandInPodExecutor) generateCreateCriCommands(experimentId string, expModel *spec.ExpModel, + containerObjectMetaList ContainerMatchedList, matchers string) ([]ExperimentIdentifierInPod, error) { + command := fmt.Sprintf("%s create cri %s %s %s", getTargetChaosBladeBin(expModel), expModel.Target, expModel.ActionName, matchers) + + identifiers := make([]ExperimentIdentifierInPod, 0) + for idx, obj := range containerObjectMetaList { + daemonsetPodName, err := e.GetChaosBladeDaemonsetPodName(obj.NodeName) + if err != nil { + logrus.WithField("experiment", experimentId). + Errorf("get chaosblade tool pod for creating failed on %s node, %v", obj.NodeName, err) + return identifiers, err + } + generatedCommand := fmt.Sprintf("%s --container-id %s --container-runtime %s", command, obj.ContainerId, + containerObjectMetaList[idx].ContainerRuntime) + identifierInPod := ExperimentIdentifierInPod{ + ContainerObjectMeta: containerObjectMetaList[idx], + Command: generatedCommand, + ChaosBladeContainerName: chaosblade.DaemonsetPodName, + ChaosBladeNamespace: chaosblade.DaemonsetPodNamespace, + ChaosBladePodName: daemonsetPodName, + } + identifiers = append(identifiers, identifierInPod) + } + return identifiers, nil +} + func (e *ExecCommandInPodExecutor) getNodeExperimentIdentifiers(experimentId string, expModel *spec.ExpModel, containerMatchedList ContainerMatchedList, matchers string, destroy bool) ([]ExperimentIdentifierInPod, error) { if destroy { return e.generateDestroyNodeCommands(experimentId, expModel, containerMatchedList, matchers) @@ -660,8 +736,12 @@ func ExcludeKeyFunc() func() map[string]spec.Empty { return GetResourceFlagNames } -func TruncateContainerObjectMetaUid(uid string) string { - return strings.ReplaceAll(uid, "docker://", "") +func TruncateContainerObjectMetaUid(uid string) (containerRuntime ,containerId string) { + if strings.HasPrefix(uid, "containerd://") { + return container.ContainerdRuntime, strings.ReplaceAll(uid, "containerd://", "") + } + + return container.DockerRuntime, strings.ReplaceAll(uid, "docker://", "") } func getDeployMode(options DeployOptions, expModel *spec.ExpModel) (DeployMode, error) { diff --git a/exec/model/filter.go b/exec/model/filter.go index c4d8442..ad6abbf 100644 --- a/exec/model/filter.go +++ b/exec/model/filter.go @@ -34,7 +34,7 @@ func GetOneAvailableContainerIdFromPod(pod v1.Pod) (containerId, containerName s if containerStatus.State.Running == nil { continue } - containerId := TruncateContainerObjectMetaUid(containerStatus.ContainerID) + _,containerId := TruncateContainerObjectMetaUid(containerStatus.ContainerID) return containerId, containerStatus.Name, nil } return "", "", fmt.Errorf("cannot find a valiable container in %s pod", pod.Name) diff --git a/exec/model/model.go b/exec/model/model.go index 9a5a472..ca7cb00 100644 --- a/exec/model/model.go +++ b/exec/model/model.go @@ -189,7 +189,14 @@ var ChaosBladeDeployModeFlag = &spec.ExpFlag{ var IsDockerNetworkFlag = &spec.ExpFlag{ Name: "is-docker-network", - Desc: "Used when a docker container is used and there is no tc command in the target container", + Desc: "Used when a docker container is used and there is no tc command in the target container. Just for docker command, Deprecated!", + NoArgs: true, + Required: false, +} + +var UseSidecarContainerNetworkFlag = &spec.ExpFlag{ + Name: "use-sidecar-container-network", + Desc: "When there is no tc command in the target container. Set the sidecar container network true.", NoArgs: true, Required: false, } @@ -197,6 +204,7 @@ var IsDockerNetworkFlag = &spec.ExpFlag{ func GetNetworkFlags() []spec.ExpFlagSpec { return []spec.ExpFlagSpec{ IsDockerNetworkFlag, + UseSidecarContainerNetworkFlag, } } @@ -241,6 +249,7 @@ func GetResourceFlagNames() map[string]spec.Empty { ChaosBladeDeployModeFlag.Name, ChaosBladeDownloadUrlFlag.Name, IsDockerNetworkFlag.Name, + UseSidecarContainerNetworkFlag.Name, } names := make(map[string]spec.Empty, 0) for _, name := range flagNames { diff --git a/version/version.go b/version/version.go index 8f2e2e7..7ee1451 100644 --- a/version/version.go +++ b/version/version.go @@ -16,8 +16,12 @@ package version -import "strings" +import ( + "strconv" + "strings" +) +const criVersion = "1.4.0" var ( Version = "unknown" Product = "community" @@ -38,3 +42,30 @@ func init() { } } } + +func CheckVerisonHaveCriCommand() bool { + verisonA := strings.Split(Version, ".") + criA := strings.Split(criVersion, ".") + if len(verisonA) != 3 { + return false + } + + for k, v := range verisonA { + vi, err := strconv.Atoi(v) + if err != nil { + return false + } + + ci, _ := strconv.Atoi(criA[k]) + + if ci == vi { + continue + } + + if vi < ci { + return false + } + return true + } + return true +} \ No newline at end of file