Compare commits
58 Commits
Author | SHA1 | Date |
---|---|---|
|
af8244e53a | |
|
0e85028f68 | |
|
63281440c1 | |
|
7e4ac4cc45 | |
|
9fb5e5a384 | |
|
0b10874e04 | |
|
77a6191735 | |
|
bb7ea39bcd | |
|
3a8ff7b8fa | |
|
e96a7ee7f1 | |
|
31aa78b0cf | |
|
9d6dfb2d65 | |
|
a4c31076d4 | |
|
2b2646ea7e | |
|
dc17ee1399 | |
|
fe0bf63328 | |
|
361a7649cb | |
|
f1afe838dd | |
|
ba4d2f704c | |
|
2d84728732 | |
|
d864dde90f | |
|
e2641540a9 | |
|
6819a4be12 | |
|
de73ffdd63 | |
|
522c4dd8d8 | |
|
d2a310ac30 | |
|
dc8f3597d3 | |
|
8909abc5c2 | |
|
d019f63af5 | |
|
ed0899559a | |
|
06ff37d414 | |
|
ccd88854bd | |
|
852d1203d4 | |
|
c97b2b90e1 | |
|
3a5f576c5b | |
|
5ea32522f0 | |
|
184224e2d2 | |
|
9cf6a6b9b7 | |
|
3998ae9f43 | |
|
aa8bea8162 | |
|
e7f9ae680a | |
|
d7645eaac5 | |
|
155d6cd729 | |
|
feb7100c35 | |
|
6b272cd656 | |
|
054c3e2a97 | |
|
66266db7fd | |
|
a47df5d5c7 | |
|
de7c74a937 | |
|
00233519bd | |
|
f3873a0417 | |
|
d39bc1fc09 | |
|
30feb53ddf | |
|
e5b440b5cd | |
|
463651570a | |
|
466b8aba39 | |
|
3d12d34d20 | |
|
b7f908ff8c |
|
@ -1,10 +0,0 @@
|
|||
component_depth: 2
|
||||
languages:
|
||||
- go
|
||||
exclude:
|
||||
- /vendor/.*
|
||||
- /pkg/client/.*
|
||||
- /pkg/apis/litmuschaos/v1alpha1/zz_generated.*\.go
|
||||
test:
|
||||
include:
|
||||
- .*/test/.*\.go
|
|
@ -2,4 +2,4 @@
|
|||
# Each line is a file pattern followed by one or more owners.
|
||||
|
||||
# These owners will be the default owners for everything in the repo.
|
||||
* @rahulchheda @ksatchit @chandankumar4 @rajdas98
|
||||
* @ksatchit @ispeakc0de @imrajdas
|
|
@ -11,7 +11,7 @@ jobs:
|
|||
# Install golang
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17.5
|
||||
go-version: 1.22
|
||||
|
||||
# Checkout to the latest commit
|
||||
# On specific directory/path
|
||||
|
@ -22,27 +22,13 @@ jobs:
|
|||
run: make gofmt-check
|
||||
|
||||
- name: golangci-lint
|
||||
uses: reviewdog/action-golangci-lint@v1
|
||||
uses: reviewdog/action-golangci-lint@v2
|
||||
with:
|
||||
golangci_lint_flags: "--timeout=10m"
|
||||
|
||||
- name: unused-package check
|
||||
run: make unused-package-check
|
||||
|
||||
security:
|
||||
container:
|
||||
image: litmuschaos/snyk:1.0
|
||||
volumes:
|
||||
- /home/runner/work/_actions/:/home/runner/work/_actions/
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: snyk/actions/setup@master
|
||||
- run: snyk auth ${SNYK_TOKEN}
|
||||
- uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: '1.17'
|
||||
- name: Snyk monitor
|
||||
run: snyk test
|
||||
|
||||
trivy:
|
||||
needs: pre-checks
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -65,6 +51,18 @@ jobs:
|
|||
vuln-type: 'os,library'
|
||||
severity: 'CRITICAL,HIGH'
|
||||
|
||||
gitleaks-scan:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Run GitLeaks
|
||||
run: |
|
||||
wget https://github.com/gitleaks/gitleaks/releases/download/v8.18.2/gitleaks_8.18.2_linux_x64.tar.gz && \
|
||||
tar -zxvf gitleaks_8.18.2_linux_x64.tar.gz && \
|
||||
sudo mv gitleaks /usr/local/bin && gitleaks detect --source . -v
|
||||
|
||||
image-build:
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre-checks
|
||||
|
@ -85,7 +83,7 @@ jobs:
|
|||
chmod +x ${{ github.workspace }}/image.tar
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: myimage
|
||||
path: |
|
||||
|
@ -98,7 +96,7 @@ jobs:
|
|||
# Install golang
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17.5
|
||||
go-version: 1.22
|
||||
|
||||
# Checkout to the latest commit
|
||||
# On specific directory/path
|
||||
|
@ -121,7 +119,7 @@ jobs:
|
|||
make deps
|
||||
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: myimage
|
||||
path: ${{ github.workspace }}
|
||||
|
@ -133,4 +131,5 @@ jobs:
|
|||
|
||||
- name: Running Go BDD Test
|
||||
run: |
|
||||
go mod tidy
|
||||
make test
|
||||
|
|
|
@ -19,7 +19,7 @@ jobs:
|
|||
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '^1.13.1'
|
||||
go-version: 1.22
|
||||
|
||||
- name: Setting up GOPATH
|
||||
run: |
|
||||
|
@ -61,12 +61,14 @@ jobs:
|
|||
- name: Installing Prerequisites (KinD Cluster)
|
||||
uses: engineerd/setup-kind@v0.5.0
|
||||
with:
|
||||
version: "v0.7.0"
|
||||
version: "v0.22.0"
|
||||
|
||||
- name: Configuring and testing kind Installation
|
||||
run: |
|
||||
kubectl cluster-info --context kind-kind
|
||||
kind get kubeconfig --internal >$HOME/.kube/config
|
||||
kubectl cluster-info
|
||||
kubectl get pods -n kube-system
|
||||
echo "current-context:" $(kubectl config current-context)
|
||||
echo "environment-kubeconfig:" ${KUBECONFIG}
|
||||
kubectl get nodes
|
||||
|
||||
- name: Load image on the nodes of the cluster
|
||||
|
@ -76,7 +78,7 @@ jobs:
|
|||
- name: Getting litmus-e2e repository
|
||||
run: |
|
||||
cd ${GOPATH}/src/github.com/litmuschaos/
|
||||
git clone https://github.com/litmuschaos/litmus-e2e.git -b generic
|
||||
git clone https://github.com/litmuschaos/litmus-e2e.git -b master
|
||||
|
||||
- name: Install LitmusChaos
|
||||
run: |
|
||||
|
@ -93,7 +95,7 @@ jobs:
|
|||
run: |
|
||||
export PATH=$PATH:$(go env GOPATH)/bin
|
||||
cd ${GOPATH}/src/github.com/litmuschaos/litmus-e2e
|
||||
go test operator/admin-mode_test.go -v -count=1
|
||||
go test components/operator/admin-mode_test.go -v -count=1
|
||||
env:
|
||||
KUBECONFIG: /home/runner/.kube/config
|
||||
|
||||
|
@ -102,7 +104,7 @@ jobs:
|
|||
run: |
|
||||
export PATH=$PATH:$(go env GOPATH)/bin
|
||||
cd ${GOPATH}/src/github.com/litmuschaos/litmus-e2e
|
||||
go test operator/reconcile-resiliency_test.go -v -count=1
|
||||
go test components/operator/reconcile-resiliency_test.go -v -count=1
|
||||
env:
|
||||
KUBECONFIG: /home/runner/.kube/config
|
||||
|
||||
|
@ -150,7 +152,7 @@ jobs:
|
|||
with:
|
||||
comment-id: "${{ github.event.comment.id }}"
|
||||
body: |
|
||||
**Test Result:** No test found
|
||||
**Test Result:** No test found try /run-e2e-all
|
||||
**Logs:** [${{ env.RUN_ID }}](https://github.com/litmuschaos/chaos-operator/actions/runs/${{ env.RUN_ID }})
|
||||
reactions: eyes
|
||||
env:
|
||||
|
|
|
@ -13,7 +13,7 @@ jobs:
|
|||
# Install golang
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17.5
|
||||
go-version: 1.22
|
||||
|
||||
# Checkout to the latest commit
|
||||
# On specific directory/path
|
||||
|
@ -24,14 +24,13 @@ jobs:
|
|||
run: make gofmt-check
|
||||
|
||||
- name: golangci-lint
|
||||
uses: reviewdog/action-golangci-lint@v1
|
||||
uses: reviewdog/action-golangci-lint@v2
|
||||
|
||||
- name: unused-package check
|
||||
run: make unused-package-check
|
||||
|
||||
image-build:
|
||||
runs-on: ubuntu-latest
|
||||
needs: tests
|
||||
steps:
|
||||
# Checkout to the latest commit
|
||||
# On specific directory/path
|
||||
|
@ -60,44 +59,3 @@ jobs:
|
|||
DNAME: ${{ secrets.DNAME }}
|
||||
DPASS: ${{ secrets.DPASS }}
|
||||
run: make push-chaos-operator
|
||||
|
||||
tests:
|
||||
needs: pre-checks
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Checkout to the latest commit
|
||||
# On specific directory/path
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Install golang
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17.5
|
||||
|
||||
#Install and configure a kind cluster
|
||||
- name: Installing Prerequisites (K3S Cluster)
|
||||
env:
|
||||
KUBECONFIG: /etc/rancher/k3s/k3s.yaml
|
||||
run: |
|
||||
curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.20.14-rc1+k3s1 sh -s - --docker --write-kubeconfig-mode 664
|
||||
kubectl wait node --all --for condition=ready --timeout=90s
|
||||
mkdir -p $HOME/.kube
|
||||
cp /etc/rancher/k3s/k3s.yaml $HOME/.kube/config
|
||||
kubectl get nodes
|
||||
|
||||
- name: Dependency checks
|
||||
run: |
|
||||
make deps
|
||||
|
||||
- name: Build Docker Image
|
||||
env:
|
||||
DOCKER_REPO: litmuschaos
|
||||
DOCKER_IMAGE: chaos-operator
|
||||
DOCKER_TAG: ci
|
||||
run: |
|
||||
make build-amd64
|
||||
|
||||
- name: Running Go BDD Test
|
||||
run: |
|
||||
make test
|
||||
|
|
|
@ -11,25 +11,15 @@ jobs:
|
|||
# Install golang
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17.5
|
||||
go-version: 1.22
|
||||
|
||||
# Checkout to the latest commit
|
||||
# On specific directory/path
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: gofmt check
|
||||
run: make gofmt-check
|
||||
|
||||
- name: golangci-lint
|
||||
uses: reviewdog/action-golangci-lint@v1
|
||||
|
||||
- name: unused-package check
|
||||
run: make unused-package-check
|
||||
|
||||
image-build:
|
||||
runs-on: ubuntu-latest
|
||||
needs: tests
|
||||
steps:
|
||||
# Checkout to the latest commit
|
||||
# On specific directory/path
|
||||
|
@ -73,44 +63,3 @@ jobs:
|
|||
DNAME: ${{ secrets.DNAME }}
|
||||
DPASS: ${{ secrets.DPASS }}
|
||||
run: make push-chaos-operator
|
||||
|
||||
tests:
|
||||
needs: pre-checks
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Checkout to the latest commit
|
||||
# On specific directory/path
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Install golang
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17.5
|
||||
|
||||
#Install and configure a kind cluster
|
||||
- name: Installing Prerequisites (K3S Cluster)
|
||||
env:
|
||||
KUBECONFIG: /etc/rancher/k3s/k3s.yaml
|
||||
run: |
|
||||
curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.20.14-rc1+k3s1 sh -s - --docker --write-kubeconfig-mode 664
|
||||
kubectl wait node --all --for condition=ready --timeout=90s
|
||||
mkdir -p $HOME/.kube
|
||||
cp /etc/rancher/k3s/k3s.yaml $HOME/.kube/config
|
||||
kubectl get nodes
|
||||
|
||||
- name: Dependency checks
|
||||
run: |
|
||||
make deps
|
||||
|
||||
- name: Build Docker Image
|
||||
env:
|
||||
DOCKER_REPO: litmuschaos
|
||||
DOCKER_IMAGE: chaos-operator
|
||||
DOCKER_TAG: ci
|
||||
run: |
|
||||
make build-amd64
|
||||
|
||||
- name: Running Go BDD Test
|
||||
run: |
|
||||
make test
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
name: Security Scan
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
trivy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Build an image from Dockerfile
|
||||
run: |
|
||||
docker build -f build/Dockerfile -t docker.io/litmuschaos/chaos-operator:${{ github.sha }} . --build-arg TARGETARCH=amd64
|
||||
|
||||
- name: Run Trivy vulnerability scanner
|
||||
uses: aquasecurity/trivy-action@master
|
||||
with:
|
||||
image-ref: 'docker.io/litmuschaos/chaos-operator:${{ github.sha }}'
|
||||
format: 'table'
|
||||
exit-code: '1'
|
||||
ignore-unfixed: true
|
||||
vuln-type: 'os,library'
|
||||
severity: 'CRITICAL,HIGH'
|
4
Makefile
4
Makefile
|
@ -74,14 +74,14 @@ build-chaos-operator:
|
|||
@echo "-------------------------"
|
||||
@echo "--> Build go-runner image"
|
||||
@echo "-------------------------"
|
||||
@docker buildx build --file build/Dockerfile --progress plane --no-cache --platform linux/arm64,linux/amd64 --tag $(DOCKER_REGISTRY)/$(DOCKER_REPO)/$(DOCKER_IMAGE):$(DOCKER_TAG) .
|
||||
@docker buildx build --file build/Dockerfile --progress plain --no-cache --platform linux/arm64,linux/amd64 --tag $(DOCKER_REGISTRY)/$(DOCKER_REPO)/$(DOCKER_IMAGE):$(DOCKER_TAG) .
|
||||
|
||||
.PHONY: push-chaos-operator
|
||||
push-chaos-operator:
|
||||
@echo "------------------------------"
|
||||
@echo "--> Pushing image"
|
||||
@echo "------------------------------"
|
||||
@docker buildx build --file build/Dockerfile --progress plane --no-cache --push --platform linux/arm64,linux/amd64 --tag $(DOCKER_REGISTRY)/$(DOCKER_REPO)/$(DOCKER_IMAGE):$(DOCKER_TAG) .
|
||||
@docker buildx build --file build/Dockerfile --progress plain --no-cache --push --platform linux/arm64,linux/amd64 --tag $(DOCKER_REGISTRY)/$(DOCKER_REPO)/$(DOCKER_IMAGE):$(DOCKER_TAG) .
|
||||
|
||||
.PHONY: build-amd64
|
||||
build-amd64:
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
[](https://www.codacy.com/manual/litmuschaos/chaos-operator?utm_source=github.com&utm_medium=referral&utm_content=litmuschaos/chaos-operator&utm_campaign=Badge_Grade)
|
||||
[](https://goreportcard.com/report/github.com/litmuschaos/chaos-operator)
|
||||
[](https://bestpractices.coreinfrastructure.org/projects/5290)
|
||||
[](https://bettercodehub.com/)
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Flitmuschaos%2Fchaos-operator?ref=badge_shield)
|
||||
[](https://codecov.io/gh/litmuschaos/chaos-operator)
|
||||
[](https://www.youtube.com/channel/UCa57PMqmz_j0wnteRa9nCaw)
|
||||
|
|
|
@ -25,13 +25,11 @@ import (
|
|||
// ChaosEngineSpec describes a user-facing custom resource which is used by developers
|
||||
// to create a chaos profile
|
||||
type ChaosEngineSpec struct {
|
||||
//Appinfo contains deployment details of AUT
|
||||
//Appinfo contains the AUT details
|
||||
Appinfo ApplicationParams `json:"appinfo,omitempty"`
|
||||
//AnnotationCheck defines whether annotation check is allowed or not. It can be true or false
|
||||
AnnotationCheck string `json:"annotationCheck,omitempty"`
|
||||
//DefaultHealthCheck defines whether default health checks should be executed or not. It can be true or false
|
||||
// default value is true
|
||||
DefaultHealthCheck string `json:"defaultHealthCheck,omitempty"`
|
||||
DefaultHealthCheck bool `json:"defaultHealthCheck,omitempty"`
|
||||
//ChaosServiceAccount is the SvcAcc specified for chaos runner pods
|
||||
ChaosServiceAccount string `json:"chaosServiceAccount"`
|
||||
//Components contains the image, imagePullPolicy, arguments, and commands of runner
|
||||
|
@ -46,6 +44,8 @@ type ChaosEngineSpec struct {
|
|||
EngineState EngineState `json:"engineState"`
|
||||
// TerminationGracePeriodSeconds contains terminationGracePeriod for the chaos resources
|
||||
TerminationGracePeriodSeconds int64 `json:"terminationGracePeriodSeconds,omitempty"`
|
||||
// Selectors contains the target application details
|
||||
Selectors *Selector `json:"selectors,omitempty"`
|
||||
}
|
||||
|
||||
// EngineState provides interface for all supported strings in spec.EngineState
|
||||
|
@ -119,10 +119,52 @@ type ApplicationParams struct {
|
|||
AppKind string `json:"appkind,omitempty"`
|
||||
}
|
||||
|
||||
type Selector struct {
|
||||
Workloads []Workload `json:"workloads,omitempty"`
|
||||
Pods []Pod `json:"pods,omitempty"`
|
||||
}
|
||||
|
||||
type WorkloadKind string
|
||||
|
||||
const (
|
||||
WorkloadDeployment WorkloadKind = "deployment"
|
||||
WorkloadStatefulSet WorkloadKind = "statefulset"
|
||||
WorkloadDaemonSet WorkloadKind = "daemonSet"
|
||||
WorkloadDeploymentConfig WorkloadKind = "deploymentconfig"
|
||||
WorkloadRollout WorkloadKind = "rollout"
|
||||
)
|
||||
|
||||
type Workload struct {
|
||||
Kind WorkloadKind `json:"kind"`
|
||||
Namespace string `json:"namespace"`
|
||||
Names string `json:"names,omitempty"`
|
||||
Labels string `json:"labels,omitempty"`
|
||||
}
|
||||
|
||||
type Pod struct {
|
||||
Namespace string `json:"namespace"`
|
||||
Names string `json:"names"`
|
||||
}
|
||||
|
||||
// ComponentParams defines information about the runner
|
||||
type ComponentParams struct {
|
||||
//Contains informations of the the runner pod
|
||||
//Contains information of the runner pod
|
||||
Runner RunnerInfo `json:"runner"`
|
||||
// Contains information of the sidecar
|
||||
Sidecar []Sidecar `json:"sidecar,omitempty"`
|
||||
}
|
||||
|
||||
type Sidecar struct {
|
||||
//Image of the sidecar container
|
||||
Image string `json:"image"`
|
||||
//ImagePullPolicy of the sidecar container
|
||||
ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"`
|
||||
// Secrets for the sidecar container
|
||||
Secrets []Secret `json:"secrets,omitempty"`
|
||||
// EnvFrom for the sidecar container
|
||||
EnvFrom []corev1.EnvFromSource `json:"envFrom"`
|
||||
// ENV contains ENV passed to the sidecar container
|
||||
ENV []corev1.EnvVar `json:"env,omitempty"`
|
||||
}
|
||||
|
||||
// RunnerInfo defines the information of the runnerinfo pod
|
||||
|
@ -166,8 +208,6 @@ type ExperimentList struct {
|
|||
|
||||
// ExperimentAttributes defines attributes of experiments
|
||||
type ExperimentAttributes struct {
|
||||
//Execution priority of the chaos experiment
|
||||
Rank uint32 `json:"rank"`
|
||||
// It contains env, configmaps, secrets, experimentImage, node selector, custom experiment annotation
|
||||
// which can be provided or overridden from the chaos engine
|
||||
Components ExperimentComponents `json:"components,omitempty"`
|
||||
|
@ -179,22 +219,24 @@ type ExperimentAttributes struct {
|
|||
// ProbeAttributes contains details of probe, which can be applied on the experiments
|
||||
type ProbeAttributes struct {
|
||||
// Name of probe
|
||||
Name string `json:"name,omitempty"`
|
||||
Name string `json:"name"`
|
||||
// Type of probe
|
||||
Type string `json:"type,omitempty"`
|
||||
Type string `json:"type"`
|
||||
// inputs needed for the k8s probe
|
||||
K8sProbeInputs K8sProbeInputs `json:"k8sProbe/inputs,omitempty"`
|
||||
K8sProbeInputs *K8sProbeInputs `json:"k8sProbe/inputs,omitempty"`
|
||||
// inputs needed for the http probe
|
||||
HTTPProbeInputs HTTPProbeInputs `json:"httpProbe/inputs,omitempty"`
|
||||
HTTPProbeInputs *HTTPProbeInputs `json:"httpProbe/inputs,omitempty"`
|
||||
// inputs needed for the cmd probe
|
||||
CmdProbeInputs CmdProbeInputs `json:"cmdProbe/inputs,omitempty"`
|
||||
CmdProbeInputs *CmdProbeInputs `json:"cmdProbe/inputs,omitempty"`
|
||||
// inputs needed for the prometheus probe
|
||||
PromProbeInputs PromProbeInputs `json:"promProbe/inputs,omitempty"`
|
||||
PromProbeInputs *PromProbeInputs `json:"promProbe/inputs,omitempty"`
|
||||
// inputs needed for the SLO probe
|
||||
SLOProbeInputs *SLOProbeInputs `json:"sloProbe/inputs,omitempty"`
|
||||
// RunProperty contains timeout, retry and interval for the probe
|
||||
RunProperties RunProperty `json:"runProperties,omitempty"`
|
||||
RunProperties RunProperty `json:"runProperties"`
|
||||
// mode for k8s probe
|
||||
// it can be SOT, EOT, Edge
|
||||
Mode string `json:"mode,omitempty"`
|
||||
Mode string `json:"mode"`
|
||||
// Data contains the manifest/data for the resource, which need to be created
|
||||
// it supported for create operation only
|
||||
Data string `json:"data,omitempty"`
|
||||
|
@ -205,9 +247,11 @@ type K8sProbeInputs struct {
|
|||
// group of the resource
|
||||
Group string `json:"group,omitempty"`
|
||||
// apiversion of the resource
|
||||
Version string `json:"version,omitempty"`
|
||||
Version string `json:"version"`
|
||||
// kind of resource
|
||||
Resource string `json:"resource,omitempty"`
|
||||
Resource string `json:"resource"`
|
||||
// ResourceNames to get the resources using their list of comma separated names
|
||||
ResourceNames string `json:"resourceNames,omitempty"`
|
||||
// namespace of the resource
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
// fieldselector to get the resource using fields selector
|
||||
|
@ -216,24 +260,24 @@ type K8sProbeInputs struct {
|
|||
LabelSelector string `json:"labelSelector,omitempty"`
|
||||
// Operation performed by the k8s probe
|
||||
// it can be create, delete, present, absent
|
||||
Operation string `json:"operation,omitempty"`
|
||||
Operation string `json:"operation"`
|
||||
}
|
||||
|
||||
//CmdProbeInputs contains all the inputs required for cmd probe
|
||||
// CmdProbeInputs contains all the inputs required for cmd probe
|
||||
type CmdProbeInputs struct {
|
||||
// Command need to be executed for the probe
|
||||
Command string `json:"command,omitempty"`
|
||||
Command string `json:"command"`
|
||||
// Comparator check for the correctness of the probe output
|
||||
Comparator ComparatorInfo `json:"comparator,omitempty"`
|
||||
Comparator ComparatorInfo `json:"comparator"`
|
||||
// The source where we have to run the command
|
||||
// It will run in inline(inside experiment itself) mode if source is nil
|
||||
Source SourceDetails `json:"source,omitempty"`
|
||||
Source *SourceDetails `json:"source,omitempty"`
|
||||
}
|
||||
|
||||
// SourceDetails contains source details of the cmdProbe
|
||||
type SourceDetails struct {
|
||||
// Image for the source pod
|
||||
Image string `json:"image,omitempty"`
|
||||
Image string `json:"image"`
|
||||
// HostNetwork define the hostNetwork of the external pod
|
||||
// it supports boolean values and default value is false
|
||||
HostNetwork bool `json:"hostNetwork,omitempty"`
|
||||
|
@ -256,6 +300,8 @@ type SourceDetails struct {
|
|||
Privileged bool `json:"privileged,omitempty"`
|
||||
// NodeSelector for the source pod
|
||||
NodeSelector map[string]string `json:"nodeSelector,omitempty"`
|
||||
// Tolerations for the source pod
|
||||
Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
|
||||
// Volumes for the source pod
|
||||
Volumes []corev1.Volume `json:"volumes,omitempty"`
|
||||
// VolumesMount for the source pod
|
||||
|
@ -264,16 +310,57 @@ type SourceDetails struct {
|
|||
ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"`
|
||||
}
|
||||
|
||||
//PromProbeInputs contains all the inputs required for prometheus probe
|
||||
// PromProbeInputs contains all the inputs required for prometheus probe
|
||||
type PromProbeInputs struct {
|
||||
// Endpoint for the prometheus probe
|
||||
Endpoint string `json:"endpoint,omitempty"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
// Query to get promethus metrics
|
||||
Query string `json:"query,omitempty"`
|
||||
// QueryPath contains filePath, which contains prometheus query
|
||||
QueryPath string `json:"queryPath,omitempty"`
|
||||
// Comparator check for the correctness of the probe output
|
||||
Comparator ComparatorInfo `json:"comparator,omitempty"`
|
||||
Comparator ComparatorInfo `json:"comparator"`
|
||||
}
|
||||
|
||||
// SLOProbeInputs contains all the inputs required for SLO probe
|
||||
type SLOProbeInputs struct {
|
||||
// PlatformEndpoint for the monitoring service endpoint
|
||||
PlatformEndpoint string `json:"platformEndpoint"`
|
||||
// SLOIdentifier for fetching the details of the SLO
|
||||
SLOIdentifier string `json:"sloIdentifier"`
|
||||
// InsecureSkipVerify flag to skip certificate checks
|
||||
InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty"`
|
||||
// EvaluationWindow is the time period for which the metrics will be evaluated
|
||||
EvaluationWindow *EvaluationWindow `json:"evaluationWindow,omitempty"`
|
||||
// SLOSourceMetadata consists of required metadata details to fetch metric data
|
||||
SLOSourceMetadata SLOSourceMetadata `json:"sloSourceMetadata"`
|
||||
// Comparator check for the correctness of the probe output
|
||||
Comparator ComparatorInfo `json:"comparator"`
|
||||
}
|
||||
|
||||
// EvaluationWindow is the time period for which the SLO probe will work
|
||||
type EvaluationWindow struct {
|
||||
// Start time of evaluation
|
||||
EvaluationStartTime int `json:"evaluationStartTime,omitempty"`
|
||||
// End time of evaluation
|
||||
EvaluationEndTime int `json:"evaluationEndTime,omitempty"`
|
||||
}
|
||||
|
||||
type SLOSourceMetadata struct {
|
||||
// APITokenSecret for authenticating with the platform service
|
||||
APITokenSecret string `json:"apiTokenSecret"`
|
||||
// Scope required for fetching details
|
||||
Scope Identifier `json:"scope"`
|
||||
}
|
||||
|
||||
// Identifier required for fetching details from the Platform APIs
|
||||
type Identifier struct {
|
||||
// AccountIdentifier for account ID
|
||||
AccountIdentifier string `json:"accountIdentifier"`
|
||||
// OrgIdentifier for organization ID
|
||||
OrgIdentifier string `json:"orgIdentifier"`
|
||||
// ProjectIdentifier for project ID
|
||||
ProjectIdentifier string `json:"projectIdentifier"`
|
||||
}
|
||||
|
||||
// ComparatorInfo contains the comparator details
|
||||
|
@ -284,34 +371,34 @@ type ComparatorInfo struct {
|
|||
// Criteria for matching data
|
||||
// it supports >=, <=, ==, >, <, != for int and float
|
||||
// it supports equal, notEqual, contains for string
|
||||
Criteria string `json:"criteria,omitempty"`
|
||||
Criteria string `json:"criteria"`
|
||||
// Value contains relative value for criteria
|
||||
Value string `json:"value,omitempty"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
//HTTPProbeInputs contains all the inputs required for http probe
|
||||
// HTTPProbeInputs contains all the inputs required for http probe
|
||||
type HTTPProbeInputs struct {
|
||||
// URL which needs to curl, to check the status
|
||||
URL string `json:"url,omitempty"`
|
||||
URL string `json:"url"`
|
||||
// InsecureSkipVerify flag to skip certificate checks
|
||||
InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty"`
|
||||
// Method define the http method, it can be get or post
|
||||
Method HTTPMethod `json:"method,omitempty"`
|
||||
Method HTTPMethod `json:"method"`
|
||||
}
|
||||
|
||||
// HTTPMethod define the http method details
|
||||
type HTTPMethod struct {
|
||||
Get GetMethod `json:"get,omitempty"`
|
||||
Post PostMethod `json:"post,omitempty"`
|
||||
Get *GetMethod `json:"get,omitempty"`
|
||||
Post *PostMethod `json:"post,omitempty"`
|
||||
}
|
||||
|
||||
// GetMethod define the http Get method
|
||||
type GetMethod struct {
|
||||
// Criteria for matching data
|
||||
// it supports == != operations
|
||||
Criteria string `json:"criteria,omitempty"`
|
||||
Criteria string `json:"criteria"`
|
||||
// Value contains relative value for criteria
|
||||
ResponseCode string `json:"responseCode,omitempty"`
|
||||
ResponseCode string `json:"responseCode"`
|
||||
}
|
||||
|
||||
// PostMethod define the http Post method
|
||||
|
@ -324,24 +411,33 @@ type PostMethod struct {
|
|||
BodyPath string `json:"bodyPath,omitempty"`
|
||||
// Criteria for matching data
|
||||
// it supports == != operations
|
||||
Criteria string `json:"criteria,omitempty"`
|
||||
Criteria string `json:"criteria"`
|
||||
// Value contains relative value for criteria
|
||||
ResponseCode string `json:"responseCode,omitempty"`
|
||||
ResponseCode string `json:"responseCode"`
|
||||
}
|
||||
|
||||
//RunProperty contains timeout, retry and interval for the probe
|
||||
// RunProperty contains timeout, retry and interval for the probe
|
||||
type RunProperty struct {
|
||||
//ProbeTimeout contains timeout for the probe
|
||||
ProbeTimeout int `json:"probeTimeout,omitempty"`
|
||||
// Interval contains the inverval for the probe
|
||||
Interval int `json:"interval,omitempty"`
|
||||
ProbeTimeout string `json:"probeTimeout"`
|
||||
// Interval contains the interval for the probe
|
||||
Interval string `json:"interval"`
|
||||
// Retry contains the retry count for the probe
|
||||
Retry int `json:"retry,omitempty"`
|
||||
// Attempt contains the total attempt count for the probe
|
||||
Attempt int `json:"attempt,omitempty"`
|
||||
//ProbePollingInterval contains time interval, for which continuous probe should be sleep
|
||||
// after each iteration
|
||||
ProbePollingInterval int `json:"probePollingInterval,omitempty"`
|
||||
ProbePollingInterval string `json:"probePollingInterval,omitempty"`
|
||||
//InitialDelaySeconds time interval for which probe will wait before run
|
||||
InitialDelaySeconds int `json:"initialDelaySeconds,omitempty"`
|
||||
//InitialDelay time interval for which probe will wait before run
|
||||
InitialDelay string `json:"initialDelay,omitempty"`
|
||||
// EvaluationTimeout is the timeout window in which the SLO metrics
|
||||
// will be fetched and will be evaluated
|
||||
EvaluationTimeout string `json:"evaluationTimeout,omitempty"`
|
||||
// Verbosity contains flags for type of logging while running the Continuous and onChaos Probes
|
||||
Verbosity string `json:"verbosity,omitempty"`
|
||||
// StopOnFailure contains flag to stop/continue experiment execution, if probe fails
|
||||
// it will stop the experiment execution, if provided true
|
||||
// it will continue the experiment execution, if provided false or not provided(default case)
|
||||
|
|
|
@ -40,8 +40,14 @@ const (
|
|||
ResultPhaseRunning ResultPhase = "Running"
|
||||
// ResultPhaseCompleted is phase of chaosresult which is in completed state
|
||||
ResultPhaseCompleted ResultPhase = "Completed"
|
||||
// Retained For Backward Compatibility: ResultPhaseCompletedWithError is phase of chaosresult when probe is failed in 3.0beta5
|
||||
ResultPhaseCompletedWithError ResultPhase = "Completed_With_Error"
|
||||
// ResultPhaseCompletedWithProbeFailure is phase of chaosresult when probe is failed from 3.0beta6
|
||||
ResultPhaseCompletedWithProbeFailure ResultPhase = "Completed_With_Probe_Failure"
|
||||
// ResultPhaseStopped is phase of chaosresult which is in stopped state
|
||||
ResultPhaseStopped ResultPhase = "Stopped"
|
||||
// ResultPhaseError is phase of chaosresult, which indicates that the experiment is terminated due to an error
|
||||
ResultPhaseError ResultPhase = "Error"
|
||||
)
|
||||
|
||||
// ResultVerdict is typecasted to string for supporting the values below.
|
||||
|
@ -54,6 +60,10 @@ const (
|
|||
ResultVerdictFailed ResultVerdict = "Fail"
|
||||
// ResultVerdictStopped is verdict of chaosresult when experiment aborted
|
||||
ResultVerdictStopped ResultVerdict = "Stopped"
|
||||
// ResultVerdictAwaited is verdict of chaosresult when experiment is yet to evaluated(experiment is in running state)
|
||||
ResultVerdictAwaited ResultVerdict = "Awaited"
|
||||
// ResultVerdictError is verdict of chaosresult when experiment is completed because of an error
|
||||
ResultVerdictError ResultVerdict = "Error"
|
||||
)
|
||||
|
||||
type ProbeVerdict string
|
||||
|
@ -116,12 +126,20 @@ type TestStatus struct {
|
|||
Phase ResultPhase `json:"phase"`
|
||||
// Verdict defines whether an experiment result is pass or fail
|
||||
Verdict ResultVerdict `json:"verdict"`
|
||||
// FailStep defines step where the experiments fails
|
||||
FailStep string `json:"failStep,omitempty"`
|
||||
// ErrorOutput defines error message and error code
|
||||
ErrorOutput *ErrorOutput `json:"errorOutput,omitempty"`
|
||||
// ProbeSuccessPercentage defines the score of the probes
|
||||
ProbeSuccessPercentage string `json:"probeSuccessPercentage,omitempty"`
|
||||
}
|
||||
|
||||
// ErrorOutput defines error reason and error code
|
||||
type ErrorOutput struct {
|
||||
// ErrorCode defines error code of the experiment
|
||||
ErrorCode string `json:"errorCode,omitempty"`
|
||||
// Reason contains the error reason
|
||||
Reason string `json:"reason,omitempty"`
|
||||
}
|
||||
|
||||
//+kubebuilder:object:root=true
|
||||
//+kubebuilder:subresource:status
|
||||
// +genclient
|
||||
|
|
|
@ -15,8 +15,8 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
// Package v1alpha1 contains API Schema definitions for the litmuschaos.io v1alpha1 API group
|
||||
//+kubebuilder:object:generate=true
|
||||
//+groupName=litmuschaos.io
|
||||
// +kubebuilder:object:generate=true
|
||||
// +groupName=litmuschaos.io
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
|
|
|
@ -113,6 +113,11 @@ func (in *ChaosEngineSpec) DeepCopyInto(out *ChaosEngineSpec) {
|
|||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Selectors != nil {
|
||||
in, out := &in.Selectors, &out.Selectors
|
||||
*out = new(Selector)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChaosEngineSpec.
|
||||
|
@ -314,7 +319,7 @@ func (in *ChaosResultSpec) DeepCopy() *ChaosResultSpec {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ChaosResultStatus) DeepCopyInto(out *ChaosResultStatus) {
|
||||
*out = *in
|
||||
out.ExperimentStatus = in.ExperimentStatus
|
||||
in.ExperimentStatus.DeepCopyInto(&out.ExperimentStatus)
|
||||
if in.ProbeStatuses != nil {
|
||||
in, out := &in.ProbeStatuses, &out.ProbeStatuses
|
||||
*out = make([]ProbeStatuses, len(*in))
|
||||
|
@ -341,7 +346,11 @@ func (in *ChaosResultStatus) DeepCopy() *ChaosResultStatus {
|
|||
func (in *CmdProbeInputs) DeepCopyInto(out *CmdProbeInputs) {
|
||||
*out = *in
|
||||
out.Comparator = in.Comparator
|
||||
in.Source.DeepCopyInto(&out.Source)
|
||||
if in.Source != nil {
|
||||
in, out := &in.Source, &out.Source
|
||||
*out = new(SourceDetails)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CmdProbeInputs.
|
||||
|
@ -373,6 +382,13 @@ func (in *ComparatorInfo) DeepCopy() *ComparatorInfo {
|
|||
func (in *ComponentParams) DeepCopyInto(out *ComponentParams) {
|
||||
*out = *in
|
||||
in.Runner.DeepCopyInto(&out.Runner)
|
||||
if in.Sidecar != nil {
|
||||
in, out := &in.Sidecar, &out.Sidecar
|
||||
*out = make([]Sidecar, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ComponentParams.
|
||||
|
@ -407,6 +423,36 @@ func (in *ConfigMap) DeepCopy() *ConfigMap {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ErrorOutput) DeepCopyInto(out *ErrorOutput) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ErrorOutput.
|
||||
func (in *ErrorOutput) DeepCopy() *ErrorOutput {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ErrorOutput)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *EvaluationWindow) DeepCopyInto(out *EvaluationWindow) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EvaluationWindow.
|
||||
func (in *EvaluationWindow) DeepCopy() *EvaluationWindow {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(EvaluationWindow)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ExperimentAttributes) DeepCopyInto(out *ExperimentAttributes) {
|
||||
*out = *in
|
||||
|
@ -613,8 +659,16 @@ func (in *GetMethod) DeepCopy() *GetMethod {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTPMethod) DeepCopyInto(out *HTTPMethod) {
|
||||
*out = *in
|
||||
out.Get = in.Get
|
||||
out.Post = in.Post
|
||||
if in.Get != nil {
|
||||
in, out := &in.Get, &out.Get
|
||||
*out = new(GetMethod)
|
||||
**out = **in
|
||||
}
|
||||
if in.Post != nil {
|
||||
in, out := &in.Post, &out.Post
|
||||
*out = new(PostMethod)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPMethod.
|
||||
|
@ -630,7 +684,7 @@ func (in *HTTPMethod) DeepCopy() *HTTPMethod {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTPProbeInputs) DeepCopyInto(out *HTTPProbeInputs) {
|
||||
*out = *in
|
||||
out.Method = in.Method
|
||||
in.Method.DeepCopyInto(&out.Method)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPProbeInputs.
|
||||
|
@ -678,6 +732,21 @@ func (in *HostFile) DeepCopy() *HostFile {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Identifier) DeepCopyInto(out *Identifier) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Identifier.
|
||||
func (in *Identifier) DeepCopy() *Identifier {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Identifier)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *K8sProbeInputs) DeepCopyInto(out *K8sProbeInputs) {
|
||||
*out = *in
|
||||
|
@ -693,6 +762,21 @@ func (in *K8sProbeInputs) DeepCopy() *K8sProbeInputs {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Pod) DeepCopyInto(out *Pod) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Pod.
|
||||
func (in *Pod) DeepCopy() *Pod {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Pod)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *PostMethod) DeepCopyInto(out *PostMethod) {
|
||||
*out = *in
|
||||
|
@ -711,10 +795,31 @@ func (in *PostMethod) DeepCopy() *PostMethod {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ProbeAttributes) DeepCopyInto(out *ProbeAttributes) {
|
||||
*out = *in
|
||||
out.K8sProbeInputs = in.K8sProbeInputs
|
||||
out.HTTPProbeInputs = in.HTTPProbeInputs
|
||||
in.CmdProbeInputs.DeepCopyInto(&out.CmdProbeInputs)
|
||||
out.PromProbeInputs = in.PromProbeInputs
|
||||
if in.K8sProbeInputs != nil {
|
||||
in, out := &in.K8sProbeInputs, &out.K8sProbeInputs
|
||||
*out = new(K8sProbeInputs)
|
||||
**out = **in
|
||||
}
|
||||
if in.HTTPProbeInputs != nil {
|
||||
in, out := &in.HTTPProbeInputs, &out.HTTPProbeInputs
|
||||
*out = new(HTTPProbeInputs)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.CmdProbeInputs != nil {
|
||||
in, out := &in.CmdProbeInputs, &out.CmdProbeInputs
|
||||
*out = new(CmdProbeInputs)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.PromProbeInputs != nil {
|
||||
in, out := &in.PromProbeInputs, &out.PromProbeInputs
|
||||
*out = new(PromProbeInputs)
|
||||
**out = **in
|
||||
}
|
||||
if in.SLOProbeInputs != nil {
|
||||
in, out := &in.SLOProbeInputs, &out.SLOProbeInputs
|
||||
*out = new(SLOProbeInputs)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
out.RunProperties = in.RunProperties
|
||||
}
|
||||
|
||||
|
@ -861,6 +966,44 @@ func (in *RunnerInfo) DeepCopy() *RunnerInfo {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SLOProbeInputs) DeepCopyInto(out *SLOProbeInputs) {
|
||||
*out = *in
|
||||
if in.EvaluationWindow != nil {
|
||||
in, out := &in.EvaluationWindow, &out.EvaluationWindow
|
||||
*out = new(EvaluationWindow)
|
||||
**out = **in
|
||||
}
|
||||
out.SLOSourceMetadata = in.SLOSourceMetadata
|
||||
out.Comparator = in.Comparator
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SLOProbeInputs.
|
||||
func (in *SLOProbeInputs) DeepCopy() *SLOProbeInputs {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SLOProbeInputs)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SLOSourceMetadata) DeepCopyInto(out *SLOSourceMetadata) {
|
||||
*out = *in
|
||||
out.Scope = in.Scope
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SLOSourceMetadata.
|
||||
func (in *SLOSourceMetadata) DeepCopy() *SLOSourceMetadata {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SLOSourceMetadata)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Secret) DeepCopyInto(out *Secret) {
|
||||
*out = *in
|
||||
|
@ -893,6 +1036,65 @@ func (in *SecurityContext) DeepCopy() *SecurityContext {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Selector) DeepCopyInto(out *Selector) {
|
||||
*out = *in
|
||||
if in.Workloads != nil {
|
||||
in, out := &in.Workloads, &out.Workloads
|
||||
*out = make([]Workload, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Pods != nil {
|
||||
in, out := &in.Pods, &out.Pods
|
||||
*out = make([]Pod, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Selector.
|
||||
func (in *Selector) DeepCopy() *Selector {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Selector)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Sidecar) DeepCopyInto(out *Sidecar) {
|
||||
*out = *in
|
||||
if in.Secrets != nil {
|
||||
in, out := &in.Secrets, &out.Secrets
|
||||
*out = make([]Secret, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.EnvFrom != nil {
|
||||
in, out := &in.EnvFrom, &out.EnvFrom
|
||||
*out = make([]v1.EnvFromSource, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.ENV != nil {
|
||||
in, out := &in.ENV, &out.ENV
|
||||
*out = make([]v1.EnvVar, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Sidecar.
|
||||
func (in *Sidecar) DeepCopy() *Sidecar {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Sidecar)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SourceDetails) DeepCopyInto(out *SourceDetails) {
|
||||
*out = *in
|
||||
|
@ -934,6 +1136,13 @@ func (in *SourceDetails) DeepCopyInto(out *SourceDetails) {
|
|||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.Tolerations != nil {
|
||||
in, out := &in.Tolerations, &out.Tolerations
|
||||
*out = make([]v1.Toleration, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Volumes != nil {
|
||||
in, out := &in.Volumes, &out.Volumes
|
||||
*out = make([]v1.Volume, len(*in))
|
||||
|
@ -998,6 +1207,11 @@ func (in *TargetDetails) DeepCopy() *TargetDetails {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TestStatus) DeepCopyInto(out *TestStatus) {
|
||||
*out = *in
|
||||
if in.ErrorOutput != nil {
|
||||
in, out := &in.ErrorOutput, &out.ErrorOutput
|
||||
*out = new(ErrorOutput)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestStatus.
|
||||
|
@ -1009,3 +1223,18 @@ func (in *TestStatus) DeepCopy() *TestStatus {
|
|||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Workload) DeepCopyInto(out *Workload) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Workload.
|
||||
func (in *Workload) DeepCopy() *Workload {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Workload)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
|
|
@ -17,13 +17,15 @@ RUN go env
|
|||
RUN CGO_ENABLED=0 go build -buildvcs=false -o /output/chaos-operator -v ./main.go
|
||||
|
||||
# Packaging stage
|
||||
# Image source: https://github.com/litmuschaos/test-tools/blob/master/custom/hardened-alpine/infra/Dockerfile
|
||||
# The base image is non-root (have litmus user) with default litmus directory.
|
||||
FROM litmuschaos/infra-alpine
|
||||
FROM registry.access.redhat.com/ubi9/ubi-minimal:9.5
|
||||
|
||||
LABEL maintainer="LitmusChaos"
|
||||
|
||||
ENV OPERATOR=/usr/local/bin/chaos-operator
|
||||
|
||||
COPY --from=builder /output/chaos-operator ${OPERATOR}
|
||||
RUN chown 65534:0 ${OPERATOR} && chmod 755 ${OPERATOR}
|
||||
|
||||
USER 65534
|
||||
|
||||
ENTRYPOINT ["/usr/local/bin/chaos-operator"]
|
||||
|
|
|
@ -19,12 +19,15 @@ package controllers
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
litmuschaosv1alpha1 "github.com/litmuschaos/chaos-operator/api/litmuschaos/v1alpha1"
|
||||
"github.com/litmuschaos/chaos-operator/pkg/analytics"
|
||||
dynamicclientset "github.com/litmuschaos/chaos-operator/pkg/client/dynamic"
|
||||
clientset "github.com/litmuschaos/chaos-operator/pkg/client/kubernetes"
|
||||
"github.com/litmuschaos/chaos-operator/pkg/resource"
|
||||
chaosTypes "github.com/litmuschaos/chaos-operator/pkg/types"
|
||||
"github.com/litmuschaos/chaos-operator/pkg/utils"
|
||||
"github.com/litmuschaos/chaos-operator/pkg/utils/retry"
|
||||
|
@ -39,14 +42,10 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"os"
|
||||
"reflect"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const finalizer = "chaosengine.litmuschaos.io/finalizer"
|
||||
|
@ -104,13 +103,16 @@ func (r *ChaosEngineReconciler) Reconcile(ctx context.Context, request ctrl.Requ
|
|||
}
|
||||
|
||||
// Start the reconcile by setting default values into ChaosEngine
|
||||
if err := r.initEngine(engine); err != nil {
|
||||
if requeue, err := r.initEngine(engine); err != nil {
|
||||
if requeue {
|
||||
return reconcile.Result{Requeue: true}, nil
|
||||
}
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// Handling of normal execution of ChaosEngine
|
||||
if engine.Instance.Spec.EngineState == litmuschaosv1alpha1.EngineStateActive && engine.Instance.Status.EngineStatus == litmuschaosv1alpha1.EngineStatusInitialized {
|
||||
return r.reconcileForCreationAndRunning(engine, reqLogger)
|
||||
return r.reconcileForCreationAndRunning(engine, *reqLogger)
|
||||
}
|
||||
|
||||
// Handling Graceful completion of ChaosEngine
|
||||
|
@ -137,24 +139,16 @@ func (r *ChaosEngineReconciler) Reconcile(ctx context.Context, request ctrl.Requ
|
|||
}
|
||||
|
||||
// getChaosRunnerENV return the env required for chaos-runner
|
||||
func getChaosRunnerENV(cr *litmuschaosv1alpha1.ChaosEngine, aExList []string, ClientUUID string) []corev1.EnvVar {
|
||||
appNS := cr.Spec.Appinfo.Appns
|
||||
if appNS == "" {
|
||||
appNS = cr.Namespace
|
||||
}
|
||||
func getChaosRunnerENV(engine *chaosTypes.EngineInfo, ClientUUID string) []corev1.EnvVar {
|
||||
|
||||
var envDetails utils.ENVDetails
|
||||
envDetails.SetEnv("CHAOSENGINE", cr.Name).
|
||||
SetEnv("APP_LABEL", cr.Spec.Appinfo.Applabel).
|
||||
SetEnv("APP_KIND", cr.Spec.Appinfo.AppKind).
|
||||
SetEnv("APP_NAMESPACE", appNS).
|
||||
SetEnv("EXPERIMENT_LIST", fmt.Sprint(strings.Join(aExList, ","))).
|
||||
SetEnv("CHAOS_SVC_ACC", cr.Spec.ChaosServiceAccount).
|
||||
SetEnv("AUXILIARY_APPINFO", cr.Spec.AuxiliaryAppInfo).
|
||||
envDetails.SetEnv("CHAOSENGINE", engine.Instance.Name).
|
||||
SetEnv("TARGETS", engine.Targets).
|
||||
SetEnv("EXPERIMENT_LIST", fmt.Sprint(strings.Join(engine.AppExperiments, ","))).
|
||||
SetEnv("CHAOS_SVC_ACC", engine.Instance.Spec.ChaosServiceAccount).
|
||||
SetEnv("AUXILIARY_APPINFO", engine.Instance.Spec.AuxiliaryAppInfo).
|
||||
SetEnv("CLIENT_UUID", ClientUUID).
|
||||
SetEnv("CHAOS_NAMESPACE", cr.Namespace).
|
||||
SetEnv("ANNOTATION_CHECK", cr.Spec.AnnotationCheck).
|
||||
SetEnv("ANNOTATION_KEY", resource.GetAnnotationKey())
|
||||
SetEnv("CHAOS_NAMESPACE", engine.Instance.Namespace)
|
||||
|
||||
return envDetails.ENV
|
||||
}
|
||||
|
@ -175,10 +169,15 @@ func getChaosRunnerLabels(cr *litmuschaosv1alpha1.ChaosEngine) map[string]string
|
|||
|
||||
// newGoRunnerPodForCR defines a new go-based Runner Pod
|
||||
func (r *ChaosEngineReconciler) newGoRunnerPodForCR(engine *chaosTypes.EngineInfo) (*corev1.Pod, error) {
|
||||
var experiment litmuschaosv1alpha1.ChaosExperiment
|
||||
if err := r.Client.Get(context.TODO(), types.NamespacedName{Name: engine.Instance.Spec.Experiments[0].Name, Namespace: engine.Instance.Namespace}, &experiment); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
engine.VolumeOpts.VolumeOperations(engine.Instance.Spec.Components.Runner.ConfigMaps, engine.Instance.Spec.Components.Runner.Secrets)
|
||||
|
||||
containerForRunner := container.NewBuilder().
|
||||
WithEnvsNew(getChaosRunnerENV(engine.Instance, engine.AppExperiments, analytics.ClientUUID)).
|
||||
WithEnvsNew(getChaosRunnerENV(engine, analytics.ClientUUID)).
|
||||
WithName("chaos-runner").
|
||||
WithImage(engine.Instance.Spec.Components.Runner.Image).
|
||||
WithImagePullPolicy(corev1.PullIfNotPresent)
|
||||
|
@ -203,6 +202,10 @@ func (r *ChaosEngineReconciler) newGoRunnerPodForCR(engine *chaosTypes.EngineInf
|
|||
containerForRunner.WithResourceRequirements(engine.Instance.Spec.Components.Runner.Resources)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(experiment.Spec.Definition.SecurityContext.ContainerSecurityContext, corev1.SecurityContext{}) {
|
||||
containerForRunner.WithSecurityContext(experiment.Spec.Definition.SecurityContext.ContainerSecurityContext)
|
||||
}
|
||||
|
||||
podForRunner := pod.NewBuilder().
|
||||
WithName(engine.Instance.Name + "-runner").
|
||||
WithNamespace(engine.Instance.Namespace).
|
||||
|
@ -228,6 +231,10 @@ func (r *ChaosEngineReconciler) newGoRunnerPodForCR(engine *chaosTypes.EngineInf
|
|||
podForRunner.WithImagePullSecrets(engine.Instance.Spec.Components.Runner.ImagePullSecrets)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(experiment.Spec.Definition.SecurityContext.PodSecurityContext, corev1.PodSecurityContext{}) {
|
||||
podForRunner.WithSecurityContext(experiment.Spec.Definition.SecurityContext.PodSecurityContext)
|
||||
}
|
||||
|
||||
runnerPod, err := podForRunner.Build()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -238,29 +245,6 @@ func (r *ChaosEngineReconciler) newGoRunnerPodForCR(engine *chaosTypes.EngineInf
|
|||
return runnerPod, nil
|
||||
}
|
||||
|
||||
// initializeApplicationInfo to initialize application info
|
||||
func initializeApplicationInfo(instance *litmuschaosv1alpha1.ChaosEngine, appInfo *chaosTypes.ApplicationInfo) (*chaosTypes.ApplicationInfo, error) {
|
||||
if instance == nil {
|
||||
return nil, errors.New("chaosengine is empty")
|
||||
}
|
||||
|
||||
if instance.Spec.Appinfo.Applabel != "" {
|
||||
appInfo.Label = instance.Spec.Appinfo.Applabel
|
||||
}
|
||||
|
||||
if instance.Spec.Appinfo.Appns != "" {
|
||||
appInfo.Namespace = instance.Spec.Appinfo.Appns
|
||||
} else {
|
||||
appInfo.Namespace = instance.Namespace
|
||||
}
|
||||
appInfo.Kind = instance.Spec.Appinfo.AppKind
|
||||
|
||||
appInfo.ExperimentList = instance.Spec.Experiments
|
||||
appInfo.ServiceAccountName = instance.Spec.ChaosServiceAccount
|
||||
|
||||
return appInfo, nil
|
||||
}
|
||||
|
||||
// engineRunnerPod to Check if the engineRunner pod already exists, else create
|
||||
func engineRunnerPod(runnerPod *podEngineRunner) error {
|
||||
if err := runnerPod.r.Client.Get(context.TODO(), types.NamespacedName{Name: runnerPod.engineRunner.Name, Namespace: runnerPod.engineRunner.Namespace}, runnerPod.pod); err != nil && k8serrors.IsNotFound(err) {
|
||||
|
@ -291,30 +275,8 @@ func (r *ChaosEngineReconciler) getChaosEngineInstance(engine *chaosTypes.Engine
|
|||
return err
|
||||
}
|
||||
engine.Instance = instance
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get application details
|
||||
func getApplicationDetail(engine *chaosTypes.EngineInfo) error {
|
||||
applicationInfo := &chaosTypes.ApplicationInfo{}
|
||||
|
||||
appInfo, err := initializeApplicationInfo(engine.Instance, applicationInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
engine.AppInfo = appInfo
|
||||
var appExperiments []string
|
||||
for _, exp := range appInfo.ExperimentList {
|
||||
appExperiments = append(appExperiments, exp.Name)
|
||||
}
|
||||
engine.AppExperiments = appExperiments
|
||||
|
||||
chaosTypes.Log.Info("App Label derived from Chaosengine is ", "appLabels", appInfo.Label)
|
||||
chaosTypes.Log.Info("App NS derived from Chaosengine is ", "appNamespace", appInfo.Namespace)
|
||||
chaosTypes.Log.Info("Exp list derived from chaosengine is ", "appExpirements", appExperiments)
|
||||
chaosTypes.Log.Info("Runner image derived from chaosengine is", "runnerImage", engine.Instance.Spec.Components.Runner.Image)
|
||||
chaosTypes.Log.Info("Annotation check is ", "annotationCheck", engine.Instance.Spec.AnnotationCheck)
|
||||
engine.AppInfo = instance.Spec.Appinfo
|
||||
engine.Selectors = instance.Spec.Selectors
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -357,19 +319,6 @@ func setChaosResourceImage(engine *chaosTypes.EngineInfo) {
|
|||
}
|
||||
}
|
||||
|
||||
// getAnnotationCheck() checks for annotation on the application
|
||||
func getAnnotationCheck(engine *chaosTypes.EngineInfo) error {
|
||||
if engine.Instance.Spec.AnnotationCheck == "" {
|
||||
engine.Instance.Spec.AnnotationCheck = chaosTypes.DefaultAnnotationCheck
|
||||
}
|
||||
|
||||
if engine.Instance.Spec.AnnotationCheck != "true" && engine.Instance.Spec.AnnotationCheck != "false" {
|
||||
return fmt.Errorf("annotationCheck '%s', is not supported it should be either true or false", engine.Instance.Spec.AnnotationCheck)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// reconcileForDelete reconciles for deletion/force deletion of Chaos Engine
|
||||
func (r *ChaosEngineReconciler) reconcileForDelete(engine *chaosTypes.EngineInfo, request reconcile.Request) (reconcile.Result, error) {
|
||||
patch := client.MergeFrom(engine.Instance.DeepCopy())
|
||||
|
@ -538,8 +487,11 @@ func (r *ChaosEngineReconciler) reconcileForRestartAfterAbort(engine *chaosTypes
|
|||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
if err := r.updateEngineForRestart(engine); err != nil {
|
||||
return reconcile.Result{}, nil
|
||||
if requeue, err := r.updateEngineForRestart(engine); err != nil {
|
||||
if requeue {
|
||||
return reconcile.Result{Requeue: true}, nil
|
||||
}
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
return reconcile.Result{}, nil
|
||||
|
@ -574,7 +526,7 @@ func (r *ChaosEngineReconciler) reconcileForRestartAfterComplete(engine *chaosTy
|
|||
}
|
||||
|
||||
// initEngine initialize Chaos Engine, and add a finalizer to it.
|
||||
func (r *ChaosEngineReconciler) initEngine(engine *chaosTypes.EngineInfo) error {
|
||||
func (r *ChaosEngineReconciler) initEngine(engine *chaosTypes.EngineInfo) (bool, error) {
|
||||
if engine.Instance.Spec.EngineState == "" {
|
||||
engine.Instance.Spec.EngineState = litmuschaosv1alpha1.EngineStateActive
|
||||
}
|
||||
|
@ -587,32 +539,29 @@ func (r *ChaosEngineReconciler) initEngine(engine *chaosTypes.EngineInfo) error
|
|||
if engine.Instance.ObjectMeta.Finalizers == nil {
|
||||
engine.Instance.ObjectMeta.Finalizers = append(engine.Instance.ObjectMeta.Finalizers, finalizer)
|
||||
if err := r.Client.Update(context.TODO(), engine.Instance, &client.UpdateOptions{}); err != nil {
|
||||
return fmt.Errorf("unable to initialize ChaosEngine, because of Update Error: %v", err)
|
||||
if k8serrors.IsConflict(err) {
|
||||
return true, err
|
||||
}
|
||||
return false, fmt.Errorf("unable to initialize ChaosEngine, because of Update Error: %v", err)
|
||||
}
|
||||
// generate the ChaosEngineInitialized event once finalizer has been added
|
||||
r.Recorder.Eventf(engine.Instance, corev1.EventTypeNormal, "ChaosEngineInitialized", "Identifying app under test & launching %s", engine.Instance.Name+"-runner")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// reconcileForCreationAndRunning reconciles for Chaos execution of Chaos Engine
|
||||
func (r *ChaosEngineReconciler) reconcileForCreationAndRunning(engine *chaosTypes.EngineInfo, reqLogger logr.Logger) (reconcile.Result, error) {
|
||||
if err := r.validateAnnotatedApplication(engine); err != nil {
|
||||
if stopEngineWithAnnotationErrorMessage := r.updateEngineState(engine, litmuschaosv1alpha1.EngineStateStop); stopEngineWithAnnotationErrorMessage != nil {
|
||||
r.Recorder.Eventf(engine.Instance, corev1.EventTypeWarning, "ChaosResourcesOperationFailed", "(chaos stop) Unable to update chaosengine")
|
||||
return reconcile.Result{}, fmt.Errorf("unable to Update Engine State: %v", err)
|
||||
var runner corev1.Pod
|
||||
if err := r.Client.Get(context.TODO(), types.NamespacedName{Name: engine.Instance.Name + "-runner", Namespace: engine.Instance.Namespace}, &runner); err != nil {
|
||||
if k8serrors.IsNotFound(err) {
|
||||
return r.createRunnerPod(engine, reqLogger)
|
||||
}
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// Check if the engineRunner pod already exists, else create
|
||||
if err := r.checkEngineRunnerPod(engine, reqLogger); err != nil {
|
||||
r.Recorder.Eventf(engine.Instance, corev1.EventTypeWarning, "ChaosResourcesOperationFailed", "(chaos start) Unable to get chaos resources")
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
isCompleted, err := r.checkRunnerContainerCompletedStatus(engine)
|
||||
if err != nil {
|
||||
if k8serrors.IsNotFound(err) {
|
||||
|
@ -623,15 +572,103 @@ func (r *ChaosEngineReconciler) reconcileForCreationAndRunning(engine *chaosType
|
|||
}
|
||||
|
||||
if isCompleted {
|
||||
if err := r.updateEngineForComplete(engine, isCompleted); err != nil {
|
||||
if requeue, err := r.updateEngineForComplete(engine, isCompleted); err != nil {
|
||||
if requeue {
|
||||
return reconcile.Result{Requeue: true}, nil
|
||||
}
|
||||
r.Recorder.Eventf(engine.Instance, corev1.EventTypeWarning, "ChaosResourcesOperationFailed", "(chaos completed) Unable to update chaos engine")
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
}
|
||||
|
||||
reqLogger.Info("Skip reconcile: engineRunner Pod already exists", "Pod.Namespace", runner.Namespace, "Pod.Name", runner.Name)
|
||||
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
||||
func (r *ChaosEngineReconciler) createRunnerPod(engine *chaosTypes.EngineInfo, reqLogger logr.Logger) (reconcile.Result, error) {
|
||||
if err := r.setExperimentDetails(engine); err != nil {
|
||||
if updateEngineErr := r.updateEngineState(engine, litmuschaosv1alpha1.EngineStateStop); updateEngineErr != nil {
|
||||
r.Recorder.Eventf(engine.Instance, corev1.EventTypeWarning, "ChaosResourcesOperationFailed", "(chaos stop) Unable to update chaosengine")
|
||||
return reconcile.Result{}, fmt.Errorf("unable to Update Engine State: %v", err)
|
||||
}
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// Check if the engineRunner pod already exists, else create
|
||||
if err := r.checkEngineRunnerPod(engine, reqLogger); err != nil {
|
||||
r.Recorder.Eventf(engine.Instance, corev1.EventTypeWarning, "ChaosResourcesOperationFailed", "(chaos start) Unable to get chaos resources")
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
||||
func (r *ChaosEngineReconciler) setExperimentDetails(engine *chaosTypes.EngineInfo) error {
|
||||
// Get the image for runner pod from chaosengine spec,operator env or default values.
|
||||
setChaosResourceImage(engine)
|
||||
|
||||
if engine.Selectors != nil && engine.Selectors.Workloads == nil && engine.Selectors.Pods == nil {
|
||||
return fmt.Errorf("specify one out of workloads or pods")
|
||||
}
|
||||
|
||||
if (engine.AppInfo.AppKind != "") != (engine.AppInfo.Applabel != "") {
|
||||
return fmt.Errorf("incomplete appinfo, provide appkind and applabel both")
|
||||
}
|
||||
|
||||
engine.Targets = getTargets(engine)
|
||||
|
||||
var appExperiments []string
|
||||
for _, exp := range engine.Instance.Spec.Experiments {
|
||||
appExperiments = append(appExperiments, exp.Name)
|
||||
}
|
||||
engine.AppExperiments = appExperiments
|
||||
|
||||
chaosTypes.Log.Info("Targets derived from Chaosengine is ", "targets", engine.Targets)
|
||||
chaosTypes.Log.Info("Exp list derived from chaosengine is ", "appExpirements", appExperiments)
|
||||
chaosTypes.Log.Info("Runner image derived from chaosengine is", "runnerImage", engine.Instance.Spec.Components.Runner.Image)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getTargets(engine *chaosTypes.EngineInfo) string {
|
||||
if engine.Selectors == nil && reflect.DeepEqual(engine.AppInfo, litmuschaosv1alpha1.ApplicationParams{}) {
|
||||
return ""
|
||||
}
|
||||
|
||||
var targets []string
|
||||
|
||||
if engine.Selectors != nil {
|
||||
if engine.Selectors.Workloads != nil {
|
||||
for _, w := range engine.Selectors.Workloads {
|
||||
var filter string
|
||||
if w.Names != "" {
|
||||
filter = w.Names
|
||||
} else {
|
||||
filter = w.Labels
|
||||
}
|
||||
|
||||
target := strings.Join([]string{string(w.Kind), w.Namespace, fmt.Sprintf("[%v]", filter)}, ":")
|
||||
targets = append(targets, target)
|
||||
}
|
||||
return strings.Join(targets, ";")
|
||||
}
|
||||
|
||||
for _, w := range engine.Selectors.Pods {
|
||||
target := strings.Join([]string{"pod", w.Namespace, fmt.Sprintf("[%v]", w.Names)}, ":")
|
||||
targets = append(targets, target)
|
||||
}
|
||||
return strings.Join(targets, ";")
|
||||
}
|
||||
|
||||
if engine.AppInfo.Appns == "" {
|
||||
engine.AppInfo.Appns = engine.Instance.Namespace
|
||||
}
|
||||
|
||||
if engine.AppInfo.AppKind == "" {
|
||||
engine.AppInfo.AppKind = "KIND"
|
||||
}
|
||||
return strings.Join([]string{engine.AppInfo.AppKind, engine.AppInfo.Appns, fmt.Sprintf("[%v]", engine.AppInfo.Applabel)}, ":")
|
||||
}
|
||||
|
||||
// updateExperimentStatusesForStop updates ChaosEngine.Status.Experiment with Abort Status.
|
||||
func updateExperimentStatusesForStop(engine *chaosTypes.EngineInfo) {
|
||||
for i := range engine.Instance.Status.Experiments {
|
||||
|
@ -643,80 +680,41 @@ func updateExperimentStatusesForStop(engine *chaosTypes.EngineInfo) {
|
|||
}
|
||||
}
|
||||
|
||||
func startReqLogger(request reconcile.Request) logr.Logger {
|
||||
func startReqLogger(request reconcile.Request) *logr.Logger {
|
||||
reqLogger := chaosTypes.Log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name)
|
||||
reqLogger.Info("Reconciling ChaosEngine")
|
||||
|
||||
return reqLogger
|
||||
return &reqLogger
|
||||
}
|
||||
|
||||
func (r *ChaosEngineReconciler) validateAnnotatedApplication(engine *chaosTypes.EngineInfo) error {
|
||||
// Get the image for runner pod from chaosengine spec,operator env or default values.
|
||||
setChaosResourceImage(engine)
|
||||
|
||||
clientSet, err := clientset.CreateClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dynamicClient, err := dynamicclientset.CreateClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// getAnnotationCheck fetch the annotationCheck from engine spec
|
||||
if err = getAnnotationCheck(engine); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Fetch the app details from ChaosEngine instance. Check if app is present
|
||||
// Also check, if the app is annotated for chaos & that the labels are unique
|
||||
if err = getApplicationDetail(engine); err != nil {
|
||||
r.Recorder.Eventf(engine.Instance, corev1.EventTypeWarning, "ChaosResourcesOperationFailed", "(appinfo derivation) Unable to get chaosengine")
|
||||
return err
|
||||
}
|
||||
|
||||
if engine.Instance.Spec.AnnotationCheck == "true" {
|
||||
if engine.AppInfo.Label == "" || engine.AppInfo.Namespace == "" || engine.AppInfo.Kind == "" {
|
||||
return errors.Errorf("incomplete AppInfo inside chaosengine")
|
||||
}
|
||||
// Determine whether apps with matching labels have chaos annotation set to true
|
||||
engine, err = resource.CheckChaosAnnotation(engine, clientSet, *dynamicClient)
|
||||
if err != nil {
|
||||
// using an event msg that indicates the app couldn't be identified. By this point in execution,
|
||||
// if the engine could not be found or accessed, it would already be caught in r.initEngine & getApplicationDetail
|
||||
r.Recorder.Eventf(engine.Instance, corev1.EventTypeWarning, "ChaosResourcesOperationFailed", "(app indentification) Unable to filter app by specified info")
|
||||
chaosTypes.Log.Info("Annotation check failed with", "error:", err)
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *ChaosEngineReconciler) updateEngineForComplete(engine *chaosTypes.EngineInfo, isCompleted bool) error {
|
||||
func (r *ChaosEngineReconciler) updateEngineForComplete(engine *chaosTypes.EngineInfo, isCompleted bool) (bool, error) {
|
||||
if engine.Instance.Status.EngineStatus != litmuschaosv1alpha1.EngineStatusCompleted {
|
||||
engine.Instance.Status.EngineStatus = litmuschaosv1alpha1.EngineStatusCompleted
|
||||
engine.Instance.Spec.EngineState = litmuschaosv1alpha1.EngineStateStop
|
||||
if err := r.Client.Update(context.TODO(), engine.Instance, &client.UpdateOptions{}); err != nil {
|
||||
return fmt.Errorf("unable to update ChaosEngine Status, due to update error: %v", err)
|
||||
if k8serrors.IsConflict(err) {
|
||||
return true, err
|
||||
}
|
||||
return false, fmt.Errorf("unable to update ChaosEngine Status, due to update error: %v", err)
|
||||
}
|
||||
r.Recorder.Eventf(engine.Instance, corev1.EventTypeNormal, "ChaosEngineCompleted", "ChaosEngine completed, will delete or retain the resources according to jobCleanUpPolicy")
|
||||
}
|
||||
|
||||
return nil
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (r *ChaosEngineReconciler) updateEngineForRestart(engine *chaosTypes.EngineInfo) error {
|
||||
func (r *ChaosEngineReconciler) updateEngineForRestart(engine *chaosTypes.EngineInfo) (bool, error) {
|
||||
r.Recorder.Eventf(engine.Instance, corev1.EventTypeNormal, "RestartInProgress", "ChaosEngine is restarted")
|
||||
engine.Instance.Status.EngineStatus = litmuschaosv1alpha1.EngineStatusInitialized
|
||||
engine.Instance.Status.Experiments = nil
|
||||
if err := r.Client.Update(context.TODO(), engine.Instance, &client.UpdateOptions{}); err != nil {
|
||||
return fmt.Errorf("unable to restart ChaosEngine, due to update error: %v", err)
|
||||
if k8serrors.IsConflict(err) {
|
||||
return true, err
|
||||
}
|
||||
return false, fmt.Errorf("unable to restart ChaosEngine, due to update error: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// updateChaosStatus update the chaos status inside the chaosresult
|
||||
|
@ -829,7 +827,7 @@ func isResultCRDAvailable() (bool, error) {
|
|||
Resource: "customresourcedefinitions",
|
||||
}
|
||||
|
||||
resultList, err := (*dynamicClient).Resource(gvr).List(context.Background(), v1.ListOptions{})
|
||||
resultList, err := dynamicClient.Resource(gvr).List(context.Background(), v1.ListOptions{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -34,61 +34,13 @@ import (
|
|||
chaosTypes "github.com/litmuschaos/chaos-operator/pkg/types"
|
||||
)
|
||||
|
||||
func TestInitializeApplicationInfo(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
instance *v1alpha1.ChaosEngine
|
||||
isErr bool
|
||||
}{
|
||||
"Test Positive-1": {
|
||||
instance: &v1alpha1.ChaosEngine{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-monitor",
|
||||
Namespace: "test",
|
||||
},
|
||||
Spec: v1alpha1.ChaosEngineSpec{
|
||||
Appinfo: v1alpha1.ApplicationParams{
|
||||
Applabel: "key=value",
|
||||
},
|
||||
},
|
||||
},
|
||||
isErr: false,
|
||||
},
|
||||
"Test Negative-1": {
|
||||
instance: nil,
|
||||
isErr: true,
|
||||
},
|
||||
}
|
||||
for name, mock := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
appInfo := &chaosTypes.ApplicationInfo{
|
||||
Namespace: "namespace",
|
||||
Label: "fake_id=aa",
|
||||
ExperimentList: []v1alpha1.ExperimentList{
|
||||
{
|
||||
Name: "fake_name",
|
||||
},
|
||||
},
|
||||
ServiceAccountName: "fake-service-account-name",
|
||||
}
|
||||
_, err := initializeApplicationInfo(mock.instance, appInfo)
|
||||
if mock.isErr && err == nil {
|
||||
t.Fatalf("Test %q failed: expected error not to be nil", name)
|
||||
}
|
||||
if !mock.isErr && err != nil {
|
||||
fmt.Println(err)
|
||||
t.Fatalf("Test %q failed: expected error to be nil", name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
func TestGetChaosRunnerENV(t *testing.T) {
|
||||
fakeEngineName := "Fake Engine"
|
||||
fakeNameSpace := "Fake NameSpace"
|
||||
fakeServiceAcc := "Fake Service Account"
|
||||
fakeTargets := "fakeTargets"
|
||||
fakeAppLabel := "Fake Label"
|
||||
fakeAppKind := "Fake Kind"
|
||||
fakeAnnotationCheck := "Fake Annotation Check"
|
||||
fakeAnnotationKey := "litmuschaos.io/chaos"
|
||||
fakeAExList := []string{"fake string"}
|
||||
fakeAuxilaryAppInfo := "ns1:name=percona,ns2:run=nginx"
|
||||
fakeClientUUID := "12345678-9012-3456-7890-123456789012"
|
||||
|
@ -106,7 +58,6 @@ func TestGetChaosRunnerENV(t *testing.T) {
|
|||
},
|
||||
Spec: v1alpha1.ChaosEngineSpec{
|
||||
ChaosServiceAccount: fakeServiceAcc,
|
||||
AnnotationCheck: fakeAnnotationCheck,
|
||||
Appinfo: v1alpha1.ApplicationParams{
|
||||
Applabel: fakeAppLabel,
|
||||
Appns: fakeNameSpace,
|
||||
|
@ -122,16 +73,8 @@ func TestGetChaosRunnerENV(t *testing.T) {
|
|||
Value: fakeEngineName,
|
||||
},
|
||||
{
|
||||
Name: "APP_LABEL",
|
||||
Value: fakeAppLabel,
|
||||
},
|
||||
{
|
||||
Name: "APP_KIND",
|
||||
Value: fakeAppKind,
|
||||
},
|
||||
{
|
||||
Name: "APP_NAMESPACE",
|
||||
Value: fakeNameSpace,
|
||||
Name: "TARGETS",
|
||||
Value: fakeTargets,
|
||||
},
|
||||
{
|
||||
Name: "EXPERIMENT_LIST",
|
||||
|
@ -153,23 +96,16 @@ func TestGetChaosRunnerENV(t *testing.T) {
|
|||
Name: "CHAOS_NAMESPACE",
|
||||
Value: fakeNameSpace,
|
||||
},
|
||||
{
|
||||
Name: "ANNOTATION_CHECK",
|
||||
Value: fakeAnnotationCheck,
|
||||
},
|
||||
{
|
||||
Name: "ANNOTATION_KEY",
|
||||
Value: fakeAnnotationKey,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for name, mock := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
actualResult := getChaosRunnerENV(mock.instance, mock.aExList, fakeClientUUID)
|
||||
println(actualResult)
|
||||
if len(actualResult) != 11 {
|
||||
t.Fatalf("Test %q failed: expected array length to be 11", name)
|
||||
engine := &chaosTypes.EngineInfo{Instance: mock.instance, Targets: fakeTargets, AppExperiments: fakeAExList}
|
||||
actualResult := getChaosRunnerENV(engine, fakeClientUUID)
|
||||
println(len(actualResult))
|
||||
if len(actualResult) != 7 {
|
||||
t.Fatalf("Test %q failed: expected array length to be 7", name)
|
||||
}
|
||||
for index, result := range actualResult {
|
||||
if result.Value != mock.expectedResult[index].Value {
|
||||
|
@ -180,260 +116,6 @@ func TestGetChaosRunnerENV(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestGetApplicationDetail(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
engine chaosTypes.EngineInfo
|
||||
isErr bool
|
||||
}{
|
||||
"Test Positive-1": {
|
||||
engine: chaosTypes.EngineInfo{
|
||||
Instance: &v1alpha1.ChaosEngine{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-monitor",
|
||||
Namespace: "test",
|
||||
},
|
||||
Spec: v1alpha1.ChaosEngineSpec{
|
||||
Appinfo: v1alpha1.ApplicationParams{
|
||||
Applabel: "key=value",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
isErr: false,
|
||||
},
|
||||
"Test Negative": {
|
||||
engine: chaosTypes.EngineInfo{
|
||||
Instance: nil,
|
||||
},
|
||||
isErr: true,
|
||||
},
|
||||
}
|
||||
for name, mock := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
err := getApplicationDetail(&mock.engine)
|
||||
if mock.isErr && err == nil {
|
||||
t.Fatalf("Test %q failed: expected error not to be nil", name)
|
||||
}
|
||||
if !mock.isErr && err != nil {
|
||||
fmt.Println(err)
|
||||
t.Fatalf("Test %q failed: expected error to be nil", name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAnnotationCheck(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
engine chaosTypes.EngineInfo
|
||||
isErr bool
|
||||
}{
|
||||
"Test Positive-1": {
|
||||
engine: chaosTypes.EngineInfo{
|
||||
Instance: &v1alpha1.ChaosEngine{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-runner",
|
||||
Namespace: "test",
|
||||
},
|
||||
Spec: v1alpha1.ChaosEngineSpec{
|
||||
ChaosServiceAccount: "fake-serviceAccount",
|
||||
Appinfo: v1alpha1.ApplicationParams{
|
||||
Applabel: "run=nginx",
|
||||
},
|
||||
AnnotationCheck: "true",
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
AppExperiments: []string{"exp-1"},
|
||||
},
|
||||
isErr: false,
|
||||
},
|
||||
"Test Positive-2": {
|
||||
engine: chaosTypes.EngineInfo{
|
||||
Instance: &v1alpha1.ChaosEngine{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-runner",
|
||||
Namespace: "test",
|
||||
},
|
||||
Spec: v1alpha1.ChaosEngineSpec{
|
||||
ChaosServiceAccount: "fake-serviceAccount",
|
||||
Appinfo: v1alpha1.ApplicationParams{
|
||||
Applabel: "run=nginx",
|
||||
},
|
||||
AnnotationCheck: "false",
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
AppExperiments: []string{"exp-1"},
|
||||
},
|
||||
|
||||
isErr: false,
|
||||
},
|
||||
"Test Negative-1": {
|
||||
engine: chaosTypes.EngineInfo{
|
||||
Instance: &v1alpha1.ChaosEngine{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-runner",
|
||||
Namespace: "test",
|
||||
},
|
||||
Spec: v1alpha1.ChaosEngineSpec{
|
||||
ChaosServiceAccount: "fake-serviceAccount",
|
||||
AnnotationCheck: "fakeCheck",
|
||||
Appinfo: v1alpha1.ApplicationParams{
|
||||
Applabel: "run=nginx",
|
||||
},
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
AppExperiments: []string{"exp-1"},
|
||||
},
|
||||
isErr: true,
|
||||
},
|
||||
}
|
||||
for name, mock := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
err := getAnnotationCheck(&mock.engine)
|
||||
if mock.isErr && err == nil {
|
||||
t.Fatalf("Test %q failed: expected error not to be nil", name)
|
||||
}
|
||||
if !mock.isErr && err != nil {
|
||||
t.Fatalf("Test %q failed: expected error to be nil", name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateAnnontatedApplication(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
engine chaosTypes.EngineInfo
|
||||
isErr bool
|
||||
}{
|
||||
"Test Positive-1": {
|
||||
engine: chaosTypes.EngineInfo{
|
||||
Instance: &v1alpha1.ChaosEngine{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "validate-annotation-p2",
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v1alpha1.ChaosEngineSpec{
|
||||
ChaosServiceAccount: "fake-serviceAccount",
|
||||
EngineState: "active",
|
||||
AnnotationCheck: "false",
|
||||
Appinfo: v1alpha1.ApplicationParams{
|
||||
Applabel: "app=nginx",
|
||||
AppKind: "deployment",
|
||||
},
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
},
|
||||
},
|
||||
Experiments: []v1alpha1.ExperimentList{
|
||||
{
|
||||
Name: "exp-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
AppExperiments: []string{"exp-1"},
|
||||
},
|
||||
|
||||
isErr: false,
|
||||
},
|
||||
"Test Negetive-1": {
|
||||
engine: chaosTypes.EngineInfo{
|
||||
Instance: &v1alpha1.ChaosEngine{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "validate-annotation-n1",
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v1alpha1.ChaosEngineSpec{
|
||||
Appinfo: v1alpha1.ApplicationParams{
|
||||
Applabel: "app=nginx",
|
||||
AppKind: "deployment",
|
||||
},
|
||||
EngineState: "active",
|
||||
AnnotationCheck: "dummy",
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
},
|
||||
},
|
||||
Experiments: []v1alpha1.ExperimentList{
|
||||
{
|
||||
Name: "exp-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
isErr: true,
|
||||
},
|
||||
"Test Negetive-2": {
|
||||
engine: chaosTypes.EngineInfo{
|
||||
Instance: &v1alpha1.ChaosEngine{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "validate-annotation-n2",
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v1alpha1.ChaosEngineSpec{
|
||||
AnnotationCheck: "true",
|
||||
EngineState: "active",
|
||||
Appinfo: v1alpha1.ApplicationParams{
|
||||
Applabel: "app=nginx",
|
||||
AppKind: "deployment",
|
||||
},
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
},
|
||||
},
|
||||
Experiments: []v1alpha1.ExperimentList{
|
||||
{
|
||||
Name: "exp-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
AppExperiments: []string{"exp-1"},
|
||||
},
|
||||
isErr: true,
|
||||
},
|
||||
}
|
||||
for name, mock := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
r := CreateFakeClient(t)
|
||||
err := r.Client.Create(context.TODO(), mock.engine.Instance)
|
||||
if err != nil {
|
||||
fmt.Printf("Unable to create engine: %v", err)
|
||||
}
|
||||
err = r.validateAnnotatedApplication(&mock.engine)
|
||||
if mock.isErr && err == nil {
|
||||
t.Fatalf("Test %q failed: expected error not to be nil", name)
|
||||
}
|
||||
if !mock.isErr && err != nil {
|
||||
t.Fatalf("Test %q failed: expected error to be nil", name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateEngineForComplete(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
engine chaosTypes.EngineInfo
|
||||
|
@ -451,8 +133,7 @@ func TestUpdateEngineForComplete(t *testing.T) {
|
|||
Applabel: "app=nginx",
|
||||
AppKind: "deployment",
|
||||
},
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
AnnotationCheck: "false",
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
|
@ -483,8 +164,7 @@ func TestUpdateEngineForComplete(t *testing.T) {
|
|||
Applabel: "app=nginx",
|
||||
AppKind: "deployment",
|
||||
},
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
AnnotationCheck: "false",
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
Experiments: []v1alpha1.ExperimentList{
|
||||
{
|
||||
Name: "exp-1",
|
||||
|
@ -510,8 +190,7 @@ func TestUpdateEngineForComplete(t *testing.T) {
|
|||
Applabel: "app=nginx",
|
||||
AppKind: "deployment",
|
||||
},
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
AnnotationCheck: "false",
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
Experiments: []v1alpha1.ExperimentList{
|
||||
{
|
||||
Name: "exp-1",
|
||||
|
@ -534,7 +213,7 @@ func TestUpdateEngineForComplete(t *testing.T) {
|
|||
fmt.Printf("Unable to create engine: %v", err)
|
||||
}
|
||||
|
||||
err = r.updateEngineForComplete(&mock.engine, true)
|
||||
_, err = r.updateEngineForComplete(&mock.engine, true)
|
||||
if mock.isErr && err == nil {
|
||||
t.Fatalf("Test %q failed: expected error not to be nil", name)
|
||||
}
|
||||
|
@ -562,8 +241,7 @@ func TestUpdateEngineForRestart(t *testing.T) {
|
|||
Applabel: "app=nginx",
|
||||
AppKind: "deployment",
|
||||
},
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
AnnotationCheck: "false",
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
|
@ -594,8 +272,7 @@ func TestUpdateEngineForRestart(t *testing.T) {
|
|||
Applabel: "app=nginx",
|
||||
AppKind: "deployment",
|
||||
},
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
AnnotationCheck: "false",
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
Experiments: []v1alpha1.ExperimentList{
|
||||
{
|
||||
Name: "exp-1",
|
||||
|
@ -618,7 +295,7 @@ func TestUpdateEngineForRestart(t *testing.T) {
|
|||
fmt.Printf("Unable to create engine: %v", err)
|
||||
}
|
||||
|
||||
err = r.updateEngineForRestart(&mock.engine)
|
||||
_, err = r.updateEngineForRestart(&mock.engine)
|
||||
if mock.isErr && err == nil {
|
||||
t.Fatalf("Test %q failed: expected error not to be nil", name)
|
||||
}
|
||||
|
@ -652,6 +329,11 @@ func TestNewGoRunnerPodForCR(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
Experiments: []v1alpha1.ExperimentList{
|
||||
{
|
||||
Name: "pod-delete",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -678,6 +360,11 @@ func TestNewGoRunnerPodForCR(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
Experiments: []v1alpha1.ExperimentList{
|
||||
{
|
||||
Name: "pod-delete",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -695,7 +382,6 @@ func TestNewGoRunnerPodForCR(t *testing.T) {
|
|||
},
|
||||
Spec: v1alpha1.ChaosEngineSpec{
|
||||
ChaosServiceAccount: "fake-serviceAccount",
|
||||
AnnotationCheck: "false",
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
|
@ -706,6 +392,11 @@ func TestNewGoRunnerPodForCR(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
Experiments: []v1alpha1.ExperimentList{
|
||||
{
|
||||
Name: "pod-delete",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -723,7 +414,6 @@ func TestNewGoRunnerPodForCR(t *testing.T) {
|
|||
},
|
||||
Spec: v1alpha1.ChaosEngineSpec{
|
||||
ChaosServiceAccount: "fake-serviceAccount",
|
||||
AnnotationCheck: "true",
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
|
@ -734,6 +424,11 @@ func TestNewGoRunnerPodForCR(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
Experiments: []v1alpha1.ExperimentList{
|
||||
{
|
||||
Name: "pod-delete",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -746,6 +441,13 @@ func TestNewGoRunnerPodForCR(t *testing.T) {
|
|||
engine: chaosTypes.EngineInfo{
|
||||
Instance: &v1alpha1.ChaosEngine{
|
||||
ObjectMeta: metav1.ObjectMeta{},
|
||||
Spec: v1alpha1.ChaosEngineSpec{
|
||||
Experiments: []v1alpha1.ExperimentList{
|
||||
{
|
||||
Name: "pod-delete",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
AppExperiments: []string{"exp-1"},
|
||||
},
|
||||
|
@ -760,6 +462,11 @@ func TestNewGoRunnerPodForCR(t *testing.T) {
|
|||
},
|
||||
Spec: v1alpha1.ChaosEngineSpec{
|
||||
ChaosServiceAccount: "fake-serviceAccount",
|
||||
Experiments: []v1alpha1.ExperimentList{
|
||||
{
|
||||
Name: "pod-delete",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -776,6 +483,11 @@ func TestNewGoRunnerPodForCR(t *testing.T) {
|
|||
},
|
||||
Spec: v1alpha1.ChaosEngineSpec{
|
||||
ChaosServiceAccount: "fake-serviceAccount",
|
||||
Experiments: []v1alpha1.ExperimentList{
|
||||
{
|
||||
Name: "pod-delete",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -797,6 +509,11 @@ func TestNewGoRunnerPodForCR(t *testing.T) {
|
|||
Image: "",
|
||||
},
|
||||
},
|
||||
Experiments: []v1alpha1.ExperimentList{
|
||||
{
|
||||
Name: "pod-delete",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -808,6 +525,15 @@ func TestNewGoRunnerPodForCR(t *testing.T) {
|
|||
for name, mock := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
r := CreateFakeClient(t)
|
||||
exp := v1alpha1.ChaosExperiment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod-delete",
|
||||
Namespace: "test",
|
||||
},
|
||||
}
|
||||
if err := r.Client.Create(context.TODO(), &exp); err != nil {
|
||||
t.Fatalf("Test %q failed: expected error not to be nil", name)
|
||||
}
|
||||
_, err := r.newGoRunnerPodForCR(&mock.engine)
|
||||
if mock.isErr && err == nil {
|
||||
t.Fatalf("Test %q failed: expected error not to be nil", name)
|
||||
|
@ -836,7 +562,6 @@ func TestInitEngine(t *testing.T) {
|
|||
Applabel: "app=nginx",
|
||||
AppKind: "deployment",
|
||||
},
|
||||
AnnotationCheck: "false",
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
|
@ -867,8 +592,7 @@ func TestInitEngine(t *testing.T) {
|
|||
Applabel: "app=nginx",
|
||||
AppKind: "deployment",
|
||||
},
|
||||
EngineState: "active",
|
||||
AnnotationCheck: "false",
|
||||
EngineState: "active",
|
||||
Experiments: []v1alpha1.ExperimentList{
|
||||
{
|
||||
Name: "exp-1",
|
||||
|
@ -886,7 +610,7 @@ func TestInitEngine(t *testing.T) {
|
|||
for name, mock := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
r := CreateFakeClient(t)
|
||||
err := r.initEngine(&mock.engine)
|
||||
_, err := r.initEngine(&mock.engine)
|
||||
if mock.isErr && err == nil {
|
||||
t.Fatalf("Test %q failed: expected error not to be nil", name)
|
||||
}
|
||||
|
@ -915,8 +639,7 @@ func TestUpdateEngineState(t *testing.T) {
|
|||
Applabel: "app=nginx",
|
||||
AppKind: "deployment",
|
||||
},
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
AnnotationCheck: "false",
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
|
@ -948,8 +671,7 @@ func TestUpdateEngineState(t *testing.T) {
|
|||
Applabel: "app=nginx",
|
||||
AppKind: "deployment",
|
||||
},
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
AnnotationCheck: "false",
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
|
@ -1005,8 +727,7 @@ func TestCheckRunnerPodCompletedStatus(t *testing.T) {
|
|||
Applabel: "app=nginx",
|
||||
AppKind: "deployment",
|
||||
},
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
AnnotationCheck: "false",
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
|
@ -1037,8 +758,7 @@ func TestCheckRunnerPodCompletedStatus(t *testing.T) {
|
|||
Applabel: "app=nginx",
|
||||
AppKind: "deployment",
|
||||
},
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
AnnotationCheck: "false",
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
|
@ -1188,8 +908,7 @@ func TestGetChaosEngineInstance(t *testing.T) {
|
|||
Applabel: "app=nginx",
|
||||
AppKind: "deployment",
|
||||
},
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
AnnotationCheck: "false",
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
|
@ -1226,8 +945,7 @@ func TestGetChaosEngineInstance(t *testing.T) {
|
|||
Applabel: "app=nginx",
|
||||
AppKind: "deployment",
|
||||
},
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
AnnotationCheck: "false",
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
|
@ -1292,6 +1010,11 @@ func TestCheckEngineRunnerPod(t *testing.T) {
|
|||
Image: "fake-runner-image",
|
||||
},
|
||||
},
|
||||
Experiments: []v1alpha1.ExperimentList{
|
||||
{
|
||||
Name: "exp-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -1313,6 +1036,11 @@ func TestCheckEngineRunnerPod(t *testing.T) {
|
|||
Image: "fake-runner-image",
|
||||
},
|
||||
},
|
||||
Experiments: []v1alpha1.ExperimentList{
|
||||
{
|
||||
Name: "exp-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -1330,12 +1058,16 @@ func TestCheckEngineRunnerPod(t *testing.T) {
|
|||
},
|
||||
Spec: v1alpha1.ChaosEngineSpec{
|
||||
ChaosServiceAccount: "fake-serviceAccount",
|
||||
AnnotationCheck: "false",
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
},
|
||||
},
|
||||
Experiments: []v1alpha1.ExperimentList{
|
||||
{
|
||||
Name: "exp-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -1353,12 +1085,16 @@ func TestCheckEngineRunnerPod(t *testing.T) {
|
|||
},
|
||||
Spec: v1alpha1.ChaosEngineSpec{
|
||||
ChaosServiceAccount: "fake-serviceAccount",
|
||||
AnnotationCheck: "true",
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
},
|
||||
},
|
||||
Experiments: []v1alpha1.ExperimentList{
|
||||
{
|
||||
Name: "exp-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -1371,6 +1107,13 @@ func TestCheckEngineRunnerPod(t *testing.T) {
|
|||
engine: chaosTypes.EngineInfo{
|
||||
Instance: &v1alpha1.ChaosEngine{
|
||||
ObjectMeta: metav1.ObjectMeta{},
|
||||
Spec: v1alpha1.ChaosEngineSpec{
|
||||
Experiments: []v1alpha1.ExperimentList{
|
||||
{
|
||||
Name: "exp-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
AppExperiments: []string{"exp-1"},
|
||||
|
@ -1386,6 +1129,11 @@ func TestCheckEngineRunnerPod(t *testing.T) {
|
|||
},
|
||||
Spec: v1alpha1.ChaosEngineSpec{
|
||||
ChaosServiceAccount: "fake-serviceAccount",
|
||||
Experiments: []v1alpha1.ExperimentList{
|
||||
{
|
||||
Name: "exp-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -1434,6 +1182,15 @@ func TestCheckEngineRunnerPod(t *testing.T) {
|
|||
for name, mock := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
r := CreateFakeClient(t)
|
||||
exp := v1alpha1.ChaosExperiment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "exp-1",
|
||||
Namespace: "test",
|
||||
},
|
||||
}
|
||||
if err := r.Client.Create(context.TODO(), &exp); err != nil {
|
||||
t.Fatalf("Test %q failed: expected error not to be nil", name)
|
||||
}
|
||||
reqLogger := chaosTypes.Log.WithValues()
|
||||
err := r.checkEngineRunnerPod(&mock.engine, reqLogger)
|
||||
if mock.isErr && err == nil {
|
||||
|
@ -1464,8 +1221,7 @@ func TestReconcileForDelete(t *testing.T) {
|
|||
Applabel: "app=nginx",
|
||||
AppKind: "deployment",
|
||||
},
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
AnnotationCheck: "false",
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
|
@ -1502,8 +1258,7 @@ func TestReconcileForDelete(t *testing.T) {
|
|||
Applabel: "app=nginx",
|
||||
AppKind: "deployment",
|
||||
},
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
AnnotationCheck: "false",
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
|
@ -1567,8 +1322,7 @@ func TestForceRemoveAllChaosPods(t *testing.T) {
|
|||
Applabel: "app=nginx",
|
||||
AppKind: "deployment",
|
||||
},
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
AnnotationCheck: "false",
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
|
@ -1605,8 +1359,7 @@ func TestForceRemoveAllChaosPods(t *testing.T) {
|
|||
Applabel: "app=nginx",
|
||||
AppKind: "deployment",
|
||||
},
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
AnnotationCheck: "false",
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1655,8 +1408,7 @@ func TestGracefullyRemoveDefaultChaosResources(t *testing.T) {
|
|||
Applabel: "app=nginx",
|
||||
AppKind: "deployment",
|
||||
},
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
AnnotationCheck: "false",
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
|
@ -1693,8 +1445,7 @@ func TestGracefullyRemoveDefaultChaosResources(t *testing.T) {
|
|||
Applabel: "app=nginx",
|
||||
AppKind: "deployment",
|
||||
},
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
AnnotationCheck: "false",
|
||||
EngineState: v1alpha1.EngineStateActive,
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
|
@ -1753,9 +1504,10 @@ func TestReconcileForCreationAndRunning(t *testing.T) {
|
|||
Spec: v1alpha1.ChaosEngineSpec{
|
||||
ChaosServiceAccount: "fake-serviceAccount",
|
||||
Appinfo: v1alpha1.ApplicationParams{
|
||||
Applabel: "run=nginx",
|
||||
Applabel: "fakeAppLabel",
|
||||
Appns: "fakeAppNs",
|
||||
AppKind: "fakeAppKind",
|
||||
},
|
||||
AnnotationCheck: "false",
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
|
@ -1769,6 +1521,12 @@ func TestReconcileForCreationAndRunning(t *testing.T) {
|
|||
},
|
||||
},
|
||||
|
||||
AppInfo: v1alpha1.ApplicationParams{
|
||||
Applabel: "fakeAppLabel",
|
||||
Appns: "fakeAppNs",
|
||||
AppKind: "fakeAppKind",
|
||||
},
|
||||
|
||||
AppExperiments: []string{"exp-1"},
|
||||
},
|
||||
isErr: false,
|
||||
|
@ -1782,9 +1540,10 @@ func TestReconcileForCreationAndRunning(t *testing.T) {
|
|||
},
|
||||
Spec: v1alpha1.ChaosEngineSpec{
|
||||
ChaosServiceAccount: "fake-serviceAccount",
|
||||
AnnotationCheck: "fakeCheck",
|
||||
Appinfo: v1alpha1.ApplicationParams{
|
||||
Applabel: "run=nginx",
|
||||
Applabel: "fakeAppLabel",
|
||||
Appns: "fakeAppNs",
|
||||
AppKind: "fakeAppKind",
|
||||
},
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
|
@ -1794,6 +1553,12 @@ func TestReconcileForCreationAndRunning(t *testing.T) {
|
|||
},
|
||||
},
|
||||
|
||||
AppInfo: v1alpha1.ApplicationParams{
|
||||
Applabel: "fakeAppLabel",
|
||||
Appns: "fakeAppNs",
|
||||
AppKind: "fakeAppKind",
|
||||
},
|
||||
|
||||
AppExperiments: []string{"exp-1"},
|
||||
},
|
||||
isErr: true,
|
||||
|
@ -1808,9 +1573,10 @@ func TestReconcileForCreationAndRunning(t *testing.T) {
|
|||
Spec: v1alpha1.ChaosEngineSpec{
|
||||
ChaosServiceAccount: "fake-serviceAccount",
|
||||
Appinfo: v1alpha1.ApplicationParams{
|
||||
Applabel: "run=nginx",
|
||||
Applabel: "fakeAppLabel",
|
||||
Appns: "fakeAppNs",
|
||||
AppKind: "fakeAppKind",
|
||||
},
|
||||
AnnotationCheck: "true",
|
||||
Components: v1alpha1.ComponentParams{
|
||||
Runner: v1alpha1.RunnerInfo{
|
||||
Image: "fake-runner-image",
|
||||
|
@ -1818,6 +1584,11 @@ func TestReconcileForCreationAndRunning(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
AppInfo: v1alpha1.ApplicationParams{
|
||||
Applabel: "fakeAppLabel",
|
||||
Appns: "fakeAppNs",
|
||||
AppKind: "fakeAppKind",
|
||||
},
|
||||
|
||||
AppExperiments: []string{"exp-1"},
|
||||
},
|
||||
|
@ -1827,6 +1598,15 @@ func TestReconcileForCreationAndRunning(t *testing.T) {
|
|||
for name, mock := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
r := CreateFakeClient(t)
|
||||
exp := v1alpha1.ChaosExperiment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "exp-1",
|
||||
Namespace: "test",
|
||||
},
|
||||
}
|
||||
if err := r.Client.Create(context.TODO(), &exp); err != nil {
|
||||
t.Fatalf("Test %q failed: expected error not to be nil", name)
|
||||
}
|
||||
reqLogger := chaosTypes.Log.WithValues()
|
||||
_, err := r.reconcileForCreationAndRunning(&mock.engine, reqLogger)
|
||||
if mock.isErr && err == nil {
|
||||
|
@ -1841,7 +1621,7 @@ func TestReconcileForCreationAndRunning(t *testing.T) {
|
|||
|
||||
func CreateFakeClient(t *testing.T) *ChaosEngineReconciler {
|
||||
|
||||
fakeClient := litmusFakeClientset.NewFakeClient()
|
||||
fakeClient := litmusFakeClientset.NewClientBuilder().WithRuntimeObjects().Build()
|
||||
if fakeClient == nil {
|
||||
fmt.Println("litmusClient is not created")
|
||||
}
|
||||
|
@ -1855,11 +1635,18 @@ func CreateFakeClient(t *testing.T) *ChaosEngineReconciler {
|
|||
},
|
||||
}
|
||||
|
||||
exp := &v1alpha1.ChaosExperiment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: make(map[string]string),
|
||||
Name: "dummyexp",
|
||||
},
|
||||
}
|
||||
|
||||
chaosResultList := &v1alpha1.ChaosResultList{
|
||||
Items: []v1alpha1.ChaosResult{},
|
||||
}
|
||||
|
||||
s.AddKnownTypes(v1alpha1.SchemeGroupVersion, engineR, chaosResultList)
|
||||
s.AddKnownTypes(v1alpha1.SchemeGroupVersion, engineR, chaosResultList, exp)
|
||||
|
||||
recorder := record.NewFakeRecorder(1024)
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -39,12 +39,8 @@ spec:
|
|||
#oneOf:
|
||||
# - pattern: '^delete$'
|
||||
# - pattern: '^retain$'
|
||||
annotationCheck:
|
||||
type: string
|
||||
pattern: ^(true|false)$
|
||||
defaultHealthCheck:
|
||||
type: string
|
||||
pattern: ^(true|false)$
|
||||
type: boolean
|
||||
appinfo:
|
||||
type: object
|
||||
properties:
|
||||
|
@ -55,6 +51,44 @@ spec:
|
|||
type: string
|
||||
appns:
|
||||
type: string
|
||||
selectors:
|
||||
type: object
|
||||
properties:
|
||||
pods:
|
||||
items:
|
||||
properties:
|
||||
names:
|
||||
type: string
|
||||
namespace:
|
||||
type: string
|
||||
required:
|
||||
- names
|
||||
- namespace
|
||||
type: object
|
||||
type: array
|
||||
workloads:
|
||||
items:
|
||||
properties:
|
||||
kind:
|
||||
type: string
|
||||
pattern: ^(^$|deployment|statefulset|daemonset|deploymentconfig|rollout)$
|
||||
labels:
|
||||
type: string
|
||||
names:
|
||||
type: string
|
||||
namespace:
|
||||
type: string
|
||||
oneOf:
|
||||
- required: [ names ]
|
||||
- required: [ labels ]
|
||||
required:
|
||||
- kind
|
||||
- namespace
|
||||
type: object
|
||||
type: array
|
||||
oneOf:
|
||||
- required: [ pods ]
|
||||
- required: [ workloads ]
|
||||
auxiliaryAppInfo:
|
||||
type: string
|
||||
engineState:
|
||||
|
@ -67,6 +101,180 @@ spec:
|
|||
components:
|
||||
type: object
|
||||
properties:
|
||||
sidecar:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
env:
|
||||
description: ENV contains ENV passed to the sidecar container
|
||||
items:
|
||||
description: EnvVar represents an environment variable
|
||||
present in a Container.
|
||||
properties:
|
||||
name:
|
||||
description: Name of the environment variable. Must
|
||||
be a C_IDENTIFIER.
|
||||
type: string
|
||||
value:
|
||||
description: 'Variable references $(VAR_NAME) are
|
||||
expanded using the previous defined environment
|
||||
variables in the container and any service environment
|
||||
variables. If a variable cannot be resolved, the
|
||||
reference in the input string will be unchanged.
|
||||
The $(VAR_NAME) syntax can be escaped with a double
|
||||
$$, ie: $$(VAR_NAME). Escaped references will never
|
||||
be expanded, regardless of whether the variable
|
||||
exists or not. Defaults to "".'
|
||||
type: string
|
||||
valueFrom:
|
||||
description: Source for the environment variable's
|
||||
value. Cannot be used if value is not empty.
|
||||
properties:
|
||||
configMapKeyRef:
|
||||
description: Selects a key of a ConfigMap.
|
||||
properties:
|
||||
key:
|
||||
description: The key to select.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info:
|
||||
https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion,
|
||||
kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the ConfigMap
|
||||
or its key must be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
fieldRef:
|
||||
description: 'Selects a field of the pod: supports
|
||||
metadata.name, metadata.namespace, `metadata.labels[''<KEY>'']`,
|
||||
`metadata.annotations[''<KEY>'']`, spec.nodeName,
|
||||
spec.serviceAccountName, status.hostIP, status.podIP,
|
||||
status.podIPs.'
|
||||
properties:
|
||||
apiVersion:
|
||||
description: Version of the schema the FieldPath
|
||||
is written in terms of, defaults to "v1".
|
||||
type: string
|
||||
fieldPath:
|
||||
description: Path of the field to select in
|
||||
the specified API version.
|
||||
type: string
|
||||
required:
|
||||
- fieldPath
|
||||
type: object
|
||||
resourceFieldRef:
|
||||
description: 'Selects a resource of the container:
|
||||
only resources limits and requests (limits.cpu,
|
||||
limits.memory, limits.ephemeral-storage, requests.cpu,
|
||||
requests.memory and requests.ephemeral-storage)
|
||||
are currently supported.'
|
||||
properties:
|
||||
containerName:
|
||||
description: 'Container name: required for
|
||||
volumes, optional for env vars'
|
||||
type: string
|
||||
divisor:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
description: Specifies the output format of
|
||||
the exposed resources, defaults to "1"
|
||||
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||
x-kubernetes-int-or-string: true
|
||||
resource:
|
||||
description: 'Required: resource to select'
|
||||
type: string
|
||||
required:
|
||||
- resource
|
||||
type: object
|
||||
secretKeyRef:
|
||||
description: Selects a key of a secret in the
|
||||
pod's namespace
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select
|
||||
from. Must be a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info:
|
||||
https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion,
|
||||
kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or
|
||||
its key must be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
type: array
|
||||
envFrom:
|
||||
description: EnvFrom for the sidecar container
|
||||
items:
|
||||
description: EnvFromSource represents the source of a
|
||||
set of ConfigMaps
|
||||
properties:
|
||||
configMapRef:
|
||||
description: The ConfigMap to select from
|
||||
properties:
|
||||
name:
|
||||
description: 'Name of the referent. More info:
|
||||
https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind,
|
||||
uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the ConfigMap must
|
||||
be defined
|
||||
type: boolean
|
||||
type: object
|
||||
prefix:
|
||||
description: An optional identifier to prepend to
|
||||
each key in the ConfigMap. Must be a C_IDENTIFIER.
|
||||
type: string
|
||||
secretRef:
|
||||
description: The Secret to select from
|
||||
properties:
|
||||
name:
|
||||
description: 'Name of the referent. More info:
|
||||
https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind,
|
||||
uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret must be
|
||||
defined
|
||||
type: boolean
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
image:
|
||||
type: string
|
||||
imagePullPolicy:
|
||||
type: string
|
||||
secrets:
|
||||
items:
|
||||
properties:
|
||||
mountPath:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
required:
|
||||
- mountPath
|
||||
- name
|
||||
type: object
|
||||
type: array
|
||||
runner:
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
type: object
|
||||
|
@ -127,6 +335,9 @@ spec:
|
|||
items:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
- type
|
||||
- mode
|
||||
- runProperties
|
||||
properties:
|
||||
name:
|
||||
|
@ -134,9 +345,13 @@ spec:
|
|||
type:
|
||||
type: string
|
||||
minLength: 1
|
||||
pattern: ^(k8sProbe|httpProbe|cmdProbe|promProbe)$
|
||||
pattern: ^(k8sProbe|httpProbe|cmdProbe|promProbe|sloProbe)$
|
||||
k8sProbe/inputs:
|
||||
type: object
|
||||
required:
|
||||
- version
|
||||
- resource
|
||||
- operation
|
||||
properties:
|
||||
group:
|
||||
type: string
|
||||
|
@ -146,6 +361,8 @@ spec:
|
|||
type: string
|
||||
namespace:
|
||||
type: string
|
||||
resourceNames:
|
||||
type: string
|
||||
fieldSelector:
|
||||
type: string
|
||||
labelSelector:
|
||||
|
@ -156,12 +373,19 @@ spec:
|
|||
minLength: 1
|
||||
cmdProbe/inputs:
|
||||
type: object
|
||||
required:
|
||||
- command
|
||||
- comparator
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
minLength: 1
|
||||
comparator:
|
||||
type: object
|
||||
required:
|
||||
- type
|
||||
- criteria
|
||||
- value
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
|
@ -174,6 +398,8 @@ spec:
|
|||
source:
|
||||
description: The external pod where we have to run the
|
||||
probe commands. It will run the commands inside the experiment pod itself(inline mode) if source contains a nil value
|
||||
required:
|
||||
- image
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
@ -349,6 +575,29 @@ spec:
|
|||
type: string
|
||||
description: NodeSelector for the source pod
|
||||
type: object
|
||||
tolerations:
|
||||
description: Tolerations for the source pod
|
||||
items:
|
||||
description: The pod with this Toleration tolerates any taint matches the <key,value,effect> using the matching operator <operator>.
|
||||
properties:
|
||||
effect:
|
||||
description: Effect to match. Empty means all effects.
|
||||
type: string
|
||||
key:
|
||||
description: Taint key the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists.
|
||||
type: string
|
||||
operator:
|
||||
description: Operators are Exists or Equal. Defaults to Equal.
|
||||
type: string
|
||||
tolerationSeconds:
|
||||
description: Period of time the toleration tolerates the taint.
|
||||
format: int64
|
||||
type: integer
|
||||
value:
|
||||
description: If the operator is Exists, the value should be empty, otherwise just a regular string.
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
privileged:
|
||||
description: Privileged for the source pod
|
||||
type: boolean
|
||||
|
@ -1957,6 +2206,9 @@ spec:
|
|||
type: object
|
||||
httpProbe/inputs:
|
||||
type: object
|
||||
required:
|
||||
- url
|
||||
- method
|
||||
properties:
|
||||
url:
|
||||
type: string
|
||||
|
@ -1969,6 +2221,9 @@ spec:
|
|||
properties:
|
||||
get:
|
||||
type: object
|
||||
required:
|
||||
- criteria
|
||||
- responseCode
|
||||
properties:
|
||||
criteria:
|
||||
type: string
|
||||
|
@ -1978,6 +2233,9 @@ spec:
|
|||
minLength: 1
|
||||
post:
|
||||
type: object
|
||||
required:
|
||||
- criteria
|
||||
- responseCode
|
||||
properties:
|
||||
contentType:
|
||||
type: string
|
||||
|
@ -1994,6 +2252,9 @@ spec:
|
|||
minLength: 1
|
||||
promProbe/inputs:
|
||||
type: object
|
||||
required:
|
||||
- endpoint
|
||||
- comparator
|
||||
properties:
|
||||
endpoint:
|
||||
type: string
|
||||
|
@ -2003,6 +2264,9 @@ spec:
|
|||
type: string
|
||||
comparator:
|
||||
type: object
|
||||
required:
|
||||
- criteria
|
||||
- value
|
||||
properties:
|
||||
criteria:
|
||||
type: string
|
||||
|
@ -2015,18 +2279,112 @@ spec:
|
|||
- probeTimeout
|
||||
- interval
|
||||
properties:
|
||||
evaluationTimeout:
|
||||
type: string
|
||||
probeTimeout:
|
||||
type: integer
|
||||
type: string
|
||||
interval:
|
||||
type: integer
|
||||
type: string
|
||||
retry:
|
||||
type: integer
|
||||
probePollingInterval:
|
||||
attempt:
|
||||
type: integer
|
||||
probePollingInterval:
|
||||
type: string
|
||||
initialDelaySeconds:
|
||||
type: integer
|
||||
initialDelay:
|
||||
type: string
|
||||
verbosity:
|
||||
type: string
|
||||
stopOnFailure:
|
||||
type: boolean
|
||||
sloProbe/inputs:
|
||||
description: inputs needed for the SLO probe
|
||||
required:
|
||||
- platformEndpoint
|
||||
- sloIdentifier
|
||||
- sloSourceMetadata
|
||||
- comparator
|
||||
properties:
|
||||
comparator:
|
||||
description: Comparator check for the correctness
|
||||
of the probe output
|
||||
required:
|
||||
- criteria
|
||||
- value
|
||||
properties:
|
||||
criteria:
|
||||
description: Criteria for matching data it
|
||||
supports >=, <=, ==, >, <, != for int and
|
||||
float it supports equal, notEqual, contains
|
||||
for string
|
||||
type: string
|
||||
type:
|
||||
description: Type of data it can be int, float,
|
||||
string
|
||||
type: string
|
||||
value:
|
||||
description: Value contains relative value
|
||||
for criteria
|
||||
type: string
|
||||
type: object
|
||||
evaluationWindow:
|
||||
description: EvaluationWindow is the time period
|
||||
for which the metrics will be evaluated
|
||||
properties:
|
||||
evaluationEndTime:
|
||||
description: End time of evaluation
|
||||
type: integer
|
||||
evaluationStartTime:
|
||||
description: Start time of evaluation
|
||||
type: integer
|
||||
type: object
|
||||
platformEndpoint:
|
||||
description: PlatformEndpoint for the monitoring
|
||||
service endpoint
|
||||
type: string
|
||||
insecureSkipVerify:
|
||||
description: InsecureSkipVerify flag to skip certificate
|
||||
checks
|
||||
type: boolean
|
||||
sloIdentifier:
|
||||
description: SLOIdentifier for fetching the details
|
||||
of the SLO
|
||||
type: string
|
||||
sloSourceMetadata:
|
||||
description: SLOSourceMetadata consists of required
|
||||
metadata details to fetch metric data
|
||||
required:
|
||||
- apiTokenSecret
|
||||
- scope
|
||||
properties:
|
||||
apiTokenSecret:
|
||||
description: APITokenSecret for authenticating
|
||||
with the platform service
|
||||
type: string
|
||||
scope:
|
||||
description: Scope required for fetching details
|
||||
required:
|
||||
- accountIdentifier
|
||||
- orgIdentifier
|
||||
- projectIdentifier
|
||||
properties:
|
||||
accountIdentifier:
|
||||
description: AccountIdentifier for account
|
||||
ID
|
||||
type: string
|
||||
orgIdentifier:
|
||||
description: OrgIdentifier for organization
|
||||
ID
|
||||
type: string
|
||||
projectIdentifier:
|
||||
description: ProjectIdentifier for project
|
||||
ID
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
type: object
|
||||
mode:
|
||||
type: string
|
||||
pattern: ^(SOT|EOT|Edge|Continuous|OnChaos)$
|
||||
|
|
|
@ -40,7 +40,7 @@ spec:
|
|||
imagePullPolicy: IfNotPresent
|
||||
env:
|
||||
- name: CHAOS_RUNNER_IMAGE
|
||||
value: "litmuschaos/chaos-runner:ci"
|
||||
value: "litmuschaos.docker.scarf.sh/litmuschaos/chaos-runner:ci"
|
||||
- name: WATCH_NAMESPACE
|
||||
value: ""
|
||||
- name: POD_NAME
|
||||
|
|
140
go.mod
140
go.mod
|
@ -1,114 +1,108 @@
|
|||
module github.com/litmuschaos/chaos-operator
|
||||
|
||||
go 1.17
|
||||
go 1.22
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.81.0 // indirect
|
||||
github.com/go-logr/logr v0.4.0
|
||||
github.com/google/go-cmp v0.5.6 // indirect
|
||||
github.com/go-logr/logr v1.4.2
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/jpillora/go-ogle-analytics v0.0.0-20161213085824-14b04e0594ef
|
||||
github.com/litmuschaos/elves v0.0.0-20201107015738-552d74669e3c
|
||||
github.com/litmuschaos/elves v0.0.0-20230607095010-c7119636b529
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c // indirect
|
||||
golang.org/x/tools v0.1.11 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
k8s.io/api v0.22.1
|
||||
k8s.io/apimachinery v0.22.1
|
||||
golang.org/x/oauth2 v0.7.0 // indirect
|
||||
k8s.io/api v0.26.15
|
||||
k8s.io/apimachinery v0.26.15
|
||||
k8s.io/client-go v12.0.0+incompatible
|
||||
sigs.k8s.io/controller-runtime v0.10.0
|
||||
sigs.k8s.io/controller-runtime v0.14.6
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24
|
||||
github.com/google/martian v2.1.0+incompatible
|
||||
github.com/onsi/ginkgo v1.16.4
|
||||
github.com/onsi/gomega v1.15.0
|
||||
github.com/operator-framework/operator-sdk v0.19.0
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/onsi/ginkgo v1.16.5
|
||||
github.com/onsi/gomega v1.24.2
|
||||
github.com/stretchr/testify v1.8.2
|
||||
k8s.io/klog v1.0.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest v0.11.18 // indirect
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/evanphx/json-patch v4.11.0+incompatible // indirect
|
||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect
|
||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||
github.com/go-logr/zapr v0.4.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
|
||||
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
|
||||
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/go-logr/zapr v1.2.3 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.0 // indirect
|
||||
github.com/go-openapi/swag v0.19.14 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/gnostic v0.5.7-v3refs // indirect
|
||||
github.com/google/gofuzz v1.1.0 // indirect
|
||||
github.com/google/uuid v1.1.2 // indirect
|
||||
github.com/googleapis/gnostic v0.5.5 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.3 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||
github.com/mailru/easyjson v0.7.6 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/nxadm/tail v1.4.8 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.12.1 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.32.1 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/prometheus/client_golang v1.14.0 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.19.0 // indirect
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect
|
||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e // indirect
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
|
||||
go.uber.org/zap v1.24.0 // indirect
|
||||
golang.org/x/net v0.19.0 // indirect
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
golang.org/x/term v0.15.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.26.0 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.22.1 // indirect
|
||||
k8s.io/component-base v0.22.2 // indirect
|
||||
k8s.io/klog/v2 v2.9.0 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e // indirect
|
||||
k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect
|
||||
sigs.k8s.io/yaml v1.2.0 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.26.1 // indirect
|
||||
k8s.io/component-base v0.26.15 // indirect
|
||||
k8s.io/klog/v2 v2.80.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
|
||||
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
|
||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||
)
|
||||
|
||||
// Pinned to kubernetes-1.21.2
|
||||
// Pinned to kubernetes-1.26
|
||||
replace (
|
||||
k8s.io/api => k8s.io/api v0.21.2
|
||||
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.21.2
|
||||
k8s.io/apimachinery => k8s.io/apimachinery v0.21.2
|
||||
k8s.io/apiserver => k8s.io/apiserver v0.21.2
|
||||
k8s.io/cli-runtime => k8s.io/cli-runtime v0.21.2
|
||||
k8s.io/client-go => k8s.io/client-go v0.21.2
|
||||
k8s.io/cloud-provider => k8s.io/cloud-provider v0.21.2
|
||||
k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.21.2
|
||||
k8s.io/code-generator => k8s.io/code-generator v0.21.2
|
||||
k8s.io/component-base => k8s.io/component-base v0.21.2
|
||||
k8s.io/cri-api => k8s.io/cri-api v0.21.2
|
||||
k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.21.2
|
||||
k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.21.2
|
||||
k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.21.2
|
||||
k8s.io/kube-proxy => k8s.io/kube-proxy v0.21.2
|
||||
k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.21.2
|
||||
k8s.io/kubectl => k8s.io/kubectl v0.21.2
|
||||
k8s.io/kubelet => k8s.io/kubelet v0.21.2
|
||||
k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.21.2
|
||||
k8s.io/metrics => k8s.io/metrics v0.21.2
|
||||
k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.21.2
|
||||
sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.14.6
|
||||
github.com/go-logr/logr => github.com/go-logr/logr v1.4.2
|
||||
k8s.io/api => k8s.io/api v0.26.15
|
||||
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.26.15
|
||||
k8s.io/apimachinery => k8s.io/apimachinery v0.26.15
|
||||
k8s.io/client-go => k8s.io/client-go v0.26.15
|
||||
k8s.io/cloud-provider => k8s.io/cloud-provider v0.26.15
|
||||
k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.26.15
|
||||
k8s.io/component-base => k8s.io/component-base v0.26.15
|
||||
k8s.io/cri-api => k8s.io/cri-api v0.26.15
|
||||
k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.26.15
|
||||
k8s.io/klog/v2 => k8s.io/klog/v2 v2.80.1
|
||||
k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.26.15
|
||||
k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.26.15
|
||||
k8s.io/kube-proxy => k8s.io/kube-proxy v0.26.15
|
||||
k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.26.15
|
||||
k8s.io/kubelet => k8s.io/kubelet v0.26.15
|
||||
k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.26.15
|
||||
k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.26.15
|
||||
)
|
||||
|
||||
replace github.com/docker/docker => github.com/moby/moby v0.7.3-0.20190826074503-38ab9da00309 // Required by Helm
|
||||
|
|
18
main.go
18
main.go
|
@ -19,9 +19,12 @@ package main
|
|||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/operator-framework/operator-sdk/pkg/k8sutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/litmuschaos/chaos-operator/pkg/analytics"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
|
||||
// to ensure that exec-entrypoint and run can make use of them.
|
||||
|
@ -69,12 +72,19 @@ func main() {
|
|||
|
||||
printVersion()
|
||||
|
||||
namespace, err := k8sutil.GetWatchNamespace()
|
||||
if err != nil {
|
||||
setupLog.Error(err, "failed to get watch namespace")
|
||||
namespace, found := os.LookupEnv("WATCH_NAMESPACE")
|
||||
if !found {
|
||||
setupLog.Error(errors.New("WATCH_NAMESPACE env is not set"), "failed to get watch namespace")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Trigger the Analytics if it's enabled
|
||||
if isAnalytics := strings.ToUpper(os.Getenv("ANALYTICS")); isAnalytics != "FALSE" {
|
||||
if err := analytics.TriggerAnalytics(); err != nil {
|
||||
setupLog.Error(err, "failed to trigger analytics")
|
||||
}
|
||||
}
|
||||
|
||||
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
|
||||
Scheme: scheme,
|
||||
MetricsBindAddress: metricsAddr,
|
||||
|
|
|
@ -37,14 +37,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{
|
|||
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
|
||||
// of clientsets, like in:
|
||||
//
|
||||
// import (
|
||||
// "k8s.io/client-go/kubernetes"
|
||||
// clientsetscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
|
||||
// )
|
||||
// import (
|
||||
// "k8s.io/client-go/kubernetes"
|
||||
// clientsetscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
|
||||
// )
|
||||
//
|
||||
// kclientset, _ := kubernetes.NewForConfig(c)
|
||||
// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
|
||||
// kclientset, _ := kubernetes.NewForConfig(c)
|
||||
// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
|
||||
//
|
||||
// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
|
||||
// correctly.
|
||||
|
|
|
@ -37,14 +37,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{
|
|||
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
|
||||
// of clientsets, like in:
|
||||
//
|
||||
// import (
|
||||
// "k8s.io/client-go/kubernetes"
|
||||
// clientsetscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
|
||||
// )
|
||||
// import (
|
||||
// "k8s.io/client-go/kubernetes"
|
||||
// clientsetscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
|
||||
// )
|
||||
//
|
||||
// kclientset, _ := kubernetes.NewForConfig(c)
|
||||
// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
|
||||
// kclientset, _ := kubernetes.NewForConfig(c)
|
||||
// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
|
||||
//
|
||||
// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
|
||||
// correctly.
|
||||
|
|
|
@ -36,9 +36,9 @@ type FakeChaosEngines struct {
|
|||
ns string
|
||||
}
|
||||
|
||||
var chaosenginesResource = schema.GroupVersionResource{Group: "litmuschaos", Version: "v1alpha1", Resource: "chaosengines"}
|
||||
var chaosenginesResource = schema.GroupVersionResource{Group: "litmuschaos.io", Version: "v1alpha1", Resource: "chaosengines"}
|
||||
|
||||
var chaosenginesKind = schema.GroupVersionKind{Group: "litmuschaos", Version: "v1alpha1", Kind: "ChaosEngine"}
|
||||
var chaosenginesKind = schema.GroupVersionKind{Group: "litmuschaos.io", Version: "v1alpha1", Kind: "ChaosEngine"}
|
||||
|
||||
// Get takes name of the chaosEngine, and returns the corresponding chaosEngine object, and an error if there is any.
|
||||
func (c *FakeChaosEngines) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ChaosEngine, err error) {
|
||||
|
|
|
@ -36,9 +36,9 @@ type FakeChaosExperiments struct {
|
|||
ns string
|
||||
}
|
||||
|
||||
var chaosexperimentsResource = schema.GroupVersionResource{Group: "litmuschaos", Version: "v1alpha1", Resource: "chaosexperiments"}
|
||||
var chaosexperimentsResource = schema.GroupVersionResource{Group: "litmuschaos.io", Version: "v1alpha1", Resource: "chaosexperiments"}
|
||||
|
||||
var chaosexperimentsKind = schema.GroupVersionKind{Group: "litmuschaos", Version: "v1alpha1", Kind: "ChaosExperiment"}
|
||||
var chaosexperimentsKind = schema.GroupVersionKind{Group: "litmuschaos.io", Version: "v1alpha1", Kind: "ChaosExperiment"}
|
||||
|
||||
// Get takes name of the chaosExperiment, and returns the corresponding chaosExperiment object, and an error if there is any.
|
||||
func (c *FakeChaosExperiments) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ChaosExperiment, err error) {
|
||||
|
|
|
@ -36,9 +36,9 @@ type FakeChaosResults struct {
|
|||
ns string
|
||||
}
|
||||
|
||||
var chaosresultsResource = schema.GroupVersionResource{Group: "litmuschaos", Version: "v1alpha1", Resource: "chaosresults"}
|
||||
var chaosresultsResource = schema.GroupVersionResource{Group: "litmuschaos.io", Version: "v1alpha1", Resource: "chaosresults"}
|
||||
|
||||
var chaosresultsKind = schema.GroupVersionKind{Group: "litmuschaos", Version: "v1alpha1", Kind: "ChaosResult"}
|
||||
var chaosresultsKind = schema.GroupVersionKind{Group: "litmuschaos.io", Version: "v1alpha1", Kind: "ChaosResult"}
|
||||
|
||||
// Get takes name of the chaosResult, and returns the corresponding chaosResult object, and an error if there is any.
|
||||
func (c *FakeChaosResults) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ChaosResult, err error) {
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
)
|
||||
|
||||
// CreateClientSet returns a Dynamic Kubernetes ClientSet
|
||||
func CreateClientSet() (*dynamic.Interface, error) {
|
||||
func CreateClientSet() (dynamic.Interface, error) {
|
||||
restConfig, err := config.GetConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -15,5 +15,5 @@ func CreateClientSet() (*dynamic.Interface, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &clientSet, nil
|
||||
return clientSet, nil
|
||||
}
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
package resource
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/dynamic"
|
||||
|
||||
chaosTypes "github.com/litmuschaos/chaos-operator/pkg/types"
|
||||
)
|
||||
|
||||
var (
|
||||
gvrro = schema.GroupVersionResource{
|
||||
Group: "argoproj.io",
|
||||
Version: "v1alpha1",
|
||||
Resource: "rollouts",
|
||||
}
|
||||
)
|
||||
|
||||
// CheckRolloutAnnotation will check the annotation of argo rollout
|
||||
func CheckRolloutAnnotation(clientSet dynamic.Interface, engine *chaosTypes.EngineInfo) (*chaosTypes.EngineInfo, error) {
|
||||
|
||||
rolloutList, err := getRolloutList(clientSet, engine)
|
||||
if err != nil {
|
||||
return engine, err
|
||||
}
|
||||
engine, chaosEnabledRollout, err := checkForChaosEnabledRollout(rolloutList, engine)
|
||||
if err != nil {
|
||||
return engine, err
|
||||
}
|
||||
|
||||
if chaosEnabledRollout == 0 {
|
||||
return engine, errors.New("no argo rollout chaos-candidate found")
|
||||
}
|
||||
|
||||
return engine, nil
|
||||
}
|
||||
|
||||
// getRolloutList returns a list of argo rollout resources that are found in the app namespace with specified label
|
||||
func getRolloutList(clientSet dynamic.Interface, engine *chaosTypes.EngineInfo) (*unstructured.UnstructuredList, error) {
|
||||
|
||||
dynamicClient := clientSet.Resource(gvrro)
|
||||
|
||||
rolloutList, err := dynamicClient.Namespace(engine.AppInfo.Namespace).List(context.Background(), metav1.ListOptions{
|
||||
LabelSelector: engine.Instance.Spec.Appinfo.Applabel})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while listing argo rollouts with matching labels %s", engine.Instance.Spec.Appinfo.Applabel)
|
||||
}
|
||||
if len(rolloutList.Items) == 0 {
|
||||
return nil, fmt.Errorf("no argo rollouts with matching labels %s", engine.Instance.Spec.Appinfo.Applabel)
|
||||
}
|
||||
return rolloutList, err
|
||||
}
|
||||
|
||||
// checkForChaosEnabledRollout will check and count the total chaos enabled application
|
||||
func checkForChaosEnabledRollout(rolloutList *unstructured.UnstructuredList, engine *chaosTypes.EngineInfo) (*chaosTypes.EngineInfo, int, error) {
|
||||
|
||||
chaosEnabledRollout := 0
|
||||
for _, rollout := range rolloutList.Items {
|
||||
annotationValue := rollout.GetAnnotations()[ChaosAnnotationKey]
|
||||
if IsChaosEnabled(annotationValue) {
|
||||
chaosTypes.Log.Info("chaos candidate of", "kind:", engine.AppInfo.Kind, "appName: ", rollout.GetName(), "appUUID: ", rollout.GetUID())
|
||||
chaosEnabledRollout++
|
||||
}
|
||||
}
|
||||
return engine, chaosEnabledRollout, nil
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
/*
|
||||
Copyright 2019 LitmusChaos Authors
|
||||
|
||||
Licensed 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 resource
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
appsV1 "k8s.io/api/apps/v1"
|
||||
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
chaosTypes "github.com/litmuschaos/chaos-operator/pkg/types"
|
||||
)
|
||||
|
||||
// CheckDaemonSetAnnotation will check the annotation of DaemonSet
|
||||
func CheckDaemonSetAnnotation(clientset kubernetes.Interface, engine *chaosTypes.EngineInfo) (*chaosTypes.EngineInfo, error) {
|
||||
targetAppList, err := getDaemonSetLists(clientset, engine)
|
||||
if err != nil {
|
||||
return engine, err
|
||||
}
|
||||
engine, chaosEnabledDaemonSet, err := checkForChaosEnabledDaemonSet(targetAppList, engine)
|
||||
if err != nil {
|
||||
return engine, err
|
||||
}
|
||||
if chaosEnabledDaemonSet == 0 {
|
||||
return engine, errors.New("no chaos-candidate found")
|
||||
}
|
||||
return engine, nil
|
||||
}
|
||||
|
||||
// getDaemonSetLists will list the daemonSets which having the chaos label
|
||||
func getDaemonSetLists(clientset kubernetes.Interface, engine *chaosTypes.EngineInfo) (*appsV1.DaemonSetList, error) {
|
||||
targetAppList, err := clientset.AppsV1().DaemonSets(engine.AppInfo.Namespace).List(context.Background(), metaV1.ListOptions{
|
||||
LabelSelector: engine.Instance.Spec.Appinfo.Applabel,
|
||||
FieldSelector: ""})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while listing daemonSets with matching labels %s", engine.Instance.Spec.Appinfo.Applabel)
|
||||
}
|
||||
if len(targetAppList.Items) == 0 {
|
||||
return nil, fmt.Errorf("no daemonSets apps with matching labels %s", engine.Instance.Spec.Appinfo.Applabel)
|
||||
}
|
||||
return targetAppList, err
|
||||
}
|
||||
|
||||
// checkForChaosEnabledDaemonSet will check and count the total chaos enabled application
|
||||
func checkForChaosEnabledDaemonSet(targetAppList *appsV1.DaemonSetList, engine *chaosTypes.EngineInfo) (*chaosTypes.EngineInfo, int, error) {
|
||||
chaosEnabledDaemonSet := 0
|
||||
for _, daemonSet := range targetAppList.Items {
|
||||
annotationValue := daemonSet.ObjectMeta.GetAnnotations()[ChaosAnnotationKey]
|
||||
if IsChaosEnabled(annotationValue) {
|
||||
chaosTypes.Log.Info("chaos candidate of", "kind:", engine.AppInfo.Kind, "appName: ", daemonSet.ObjectMeta.Name, "appUUID: ", daemonSet.ObjectMeta.UID)
|
||||
chaosEnabledDaemonSet++
|
||||
}
|
||||
}
|
||||
return engine, chaosEnabledDaemonSet, nil
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
/*
|
||||
Copyright 2019 LitmusChaos Authors
|
||||
|
||||
Licensed 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 resource
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
v1 "k8s.io/api/apps/v1"
|
||||
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
chaosTypes "github.com/litmuschaos/chaos-operator/pkg/types"
|
||||
)
|
||||
|
||||
// CheckDeploymentAnnotation will check the annotation of deployment
|
||||
func CheckDeploymentAnnotation(clientset kubernetes.Interface, engine *chaosTypes.EngineInfo) (*chaosTypes.EngineInfo, error) {
|
||||
targetAppList, err := getDeploymentLists(clientset, engine)
|
||||
if err != nil {
|
||||
return engine, err
|
||||
}
|
||||
engine, chaosEnabledDeployment, err := checkForChaosEnabledDeployment(targetAppList, engine)
|
||||
if err != nil {
|
||||
return engine, err
|
||||
}
|
||||
if chaosEnabledDeployment == 0 {
|
||||
return engine, errors.New("no chaos-candidate found")
|
||||
}
|
||||
return engine, nil
|
||||
}
|
||||
|
||||
// getDeploymentLists will list the deployments which having the chaos label
|
||||
func getDeploymentLists(clientset kubernetes.Interface, engine *chaosTypes.EngineInfo) (*v1.DeploymentList, error) {
|
||||
targetAppList, err := clientset.AppsV1().Deployments(engine.AppInfo.Namespace).List(context.Background(), metaV1.ListOptions{
|
||||
LabelSelector: engine.Instance.Spec.Appinfo.Applabel,
|
||||
FieldSelector: ""})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while listing deployments with matching labels %s", engine.Instance.Spec.Appinfo.Applabel)
|
||||
}
|
||||
if len(targetAppList.Items) == 0 {
|
||||
return nil, fmt.Errorf("no deployments apps with matching labels %s", engine.Instance.Spec.Appinfo.Applabel)
|
||||
}
|
||||
return targetAppList, err
|
||||
}
|
||||
|
||||
// checkForChaosEnabledDeployment will check and count the total chaos enabled application
|
||||
func checkForChaosEnabledDeployment(targetAppList *v1.DeploymentList, engine *chaosTypes.EngineInfo) (*chaosTypes.EngineInfo, int, error) {
|
||||
chaosEnabledDeployment := 0
|
||||
for _, deployment := range targetAppList.Items {
|
||||
annotationValue := deployment.ObjectMeta.GetAnnotations()[ChaosAnnotationKey]
|
||||
if IsChaosEnabled(annotationValue) {
|
||||
chaosTypes.Log.Info("chaos candidate of", "kind:", engine.AppInfo.Kind, "appName: ", deployment.ObjectMeta.Name, "appUUID: ", deployment.ObjectMeta.UID)
|
||||
chaosEnabledDeployment++
|
||||
}
|
||||
}
|
||||
return engine, chaosEnabledDeployment, nil
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
package resource
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/dynamic"
|
||||
|
||||
chaosTypes "github.com/litmuschaos/chaos-operator/pkg/types"
|
||||
)
|
||||
|
||||
var (
|
||||
gvrdc = schema.GroupVersionResource{
|
||||
Group: "apps.openshift.io",
|
||||
Version: "v1",
|
||||
Resource: "deploymentconfigs",
|
||||
}
|
||||
)
|
||||
|
||||
// CheckDeploymentConfigAnnotation will check the annotation of deployment
|
||||
func CheckDeploymentConfigAnnotation(clientSet dynamic.Interface, engine *chaosTypes.EngineInfo) (*chaosTypes.EngineInfo, error) {
|
||||
deploymentConfigList, err := getDeploymentConfigList(clientSet, engine)
|
||||
if err != nil {
|
||||
return engine, err
|
||||
}
|
||||
|
||||
engine, chaosEnabledDeploymentConfig, err := checkForChaosEnabledDeploymentConfig(deploymentConfigList, engine)
|
||||
if err != nil {
|
||||
return engine, err
|
||||
}
|
||||
|
||||
if chaosEnabledDeploymentConfig == 0 {
|
||||
return engine, errors.New("no deploymentconfigs chaos-candidate found")
|
||||
}
|
||||
|
||||
return engine, nil
|
||||
}
|
||||
|
||||
func getDeploymentConfigList(clientSet dynamic.Interface, engine *chaosTypes.EngineInfo) (*unstructured.UnstructuredList, error) {
|
||||
dynamicClient := clientSet.Resource(gvrdc)
|
||||
|
||||
deploymentConfigList, err := dynamicClient.Namespace(engine.AppInfo.Namespace).List(context.Background(), metav1.ListOptions{
|
||||
LabelSelector: engine.Instance.Spec.Appinfo.Applabel})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while listing deploymentconfigs with matching labels: %s", engine.Instance.Spec.Appinfo.Applabel)
|
||||
}
|
||||
|
||||
if len(deploymentConfigList.Items) == 0 {
|
||||
return nil, fmt.Errorf("no deploymentconfigs with matching labels: %s", engine.Instance.Spec.Appinfo.Applabel)
|
||||
}
|
||||
|
||||
return deploymentConfigList, err
|
||||
}
|
||||
|
||||
// checkForChaosEnabledDeploymentConfig will check and count the total chaos enabled application
|
||||
func checkForChaosEnabledDeploymentConfig(deploymentConfigList *unstructured.UnstructuredList, engine *chaosTypes.EngineInfo) (*chaosTypes.EngineInfo, int, error) {
|
||||
chaosEnabledDeploymentConfig := 0
|
||||
if deploymentConfigList == nil {
|
||||
return engine, chaosEnabledDeploymentConfig, fmt.Errorf("deploymentconfigs is nil")
|
||||
}
|
||||
|
||||
for _, deploymentConfig := range deploymentConfigList.Items {
|
||||
annotationValue := deploymentConfig.GetAnnotations()[ChaosAnnotationKey]
|
||||
if IsChaosEnabled(annotationValue) {
|
||||
chaosTypes.Log.Info("chaos candidate of", "kind:", engine.AppInfo.Kind, "appName: ", deploymentConfig.GetName(), "appUUID: ", deploymentConfig.GetUID())
|
||||
chaosEnabledDeploymentConfig++
|
||||
}
|
||||
}
|
||||
|
||||
return engine, chaosEnabledDeploymentConfig, nil
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
/*
|
||||
Copyright 2019 LitmusChaos Authors
|
||||
|
||||
Licensed 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 resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
chaosTypes "github.com/litmuschaos/chaos-operator/pkg/types"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
// Annotations on app to enable chaos on it
|
||||
const (
|
||||
ChaosAnnotationValue = "true"
|
||||
DefaultChaosAnnotationKey = "litmuschaos.io/chaos"
|
||||
)
|
||||
|
||||
var (
|
||||
// ChaosAnnotationKey is global variable used as the Key for annotation check.
|
||||
ChaosAnnotationKey = GetAnnotationKey()
|
||||
)
|
||||
|
||||
// GetAnnotationKey returns the annotation to be used while validating applications.
|
||||
func GetAnnotationKey() string {
|
||||
|
||||
annotationKey := os.Getenv("CUSTOM_ANNOTATION")
|
||||
if len(annotationKey) != 0 {
|
||||
return annotationKey
|
||||
}
|
||||
return DefaultChaosAnnotationKey
|
||||
|
||||
}
|
||||
|
||||
// CheckChaosAnnotation will check for the annotation of required resources
|
||||
func CheckChaosAnnotation(engine *chaosTypes.EngineInfo, clientset kubernetes.Interface, dynamicClientSet dynamic.Interface) (*chaosTypes.EngineInfo, error) {
|
||||
|
||||
switch strings.ToLower(engine.AppInfo.Kind) {
|
||||
case "deployment", "deployments":
|
||||
engine, err := CheckDeploymentAnnotation(clientset, engine)
|
||||
if err != nil {
|
||||
return engine, fmt.Errorf("resource type 'deployment', err: %+v", err)
|
||||
}
|
||||
case "statefulset", "statefulsets":
|
||||
engine, err := CheckStatefulSetAnnotation(clientset, engine)
|
||||
if err != nil {
|
||||
return engine, fmt.Errorf("resource type 'statefulset', err: %+v", err)
|
||||
}
|
||||
case "daemonset", "daemonsets":
|
||||
engine, err := CheckDaemonSetAnnotation(clientset, engine)
|
||||
if err != nil {
|
||||
return engine, fmt.Errorf("resource type 'daemonset', err: %+v", err)
|
||||
}
|
||||
case "deploymentconfig", "deploymentconfigs":
|
||||
engine, err := CheckDeploymentConfigAnnotation(dynamicClientSet, engine)
|
||||
if err != nil {
|
||||
return engine, fmt.Errorf("resource type 'deploymentconfig', err: %+v", err)
|
||||
}
|
||||
case "rollout", "rollouts":
|
||||
engine, err := CheckRolloutAnnotation(dynamicClientSet, engine)
|
||||
if err != nil {
|
||||
return engine, fmt.Errorf("resource type 'rollout', err: %+v", err)
|
||||
}
|
||||
default:
|
||||
return engine, fmt.Errorf("resource type '%s' not supported for induce chaos", engine.AppInfo.Kind)
|
||||
}
|
||||
return engine, nil
|
||||
}
|
||||
|
||||
// IsChaosEnabled check for the given annotation value
|
||||
func IsChaosEnabled(annotationValue string) bool {
|
||||
return annotationValue == ChaosAnnotationValue
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,72 +0,0 @@
|
|||
/*
|
||||
Copyright 2019 LitmusChaos Authors
|
||||
|
||||
Licensed 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 resource
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
appsV1 "k8s.io/api/apps/v1"
|
||||
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
chaosTypes "github.com/litmuschaos/chaos-operator/pkg/types"
|
||||
)
|
||||
|
||||
// CheckStatefulSetAnnotation will check the annotation of StatefulSet
|
||||
func CheckStatefulSetAnnotation(clientset kubernetes.Interface, engine *chaosTypes.EngineInfo) (*chaosTypes.EngineInfo, error) {
|
||||
targetAppList, err := getStatefulSetLists(clientset, engine)
|
||||
if err != nil {
|
||||
return engine, err
|
||||
}
|
||||
engine, chaosEnabledStatefulSet, err := checkForChaosEnabledStatefulSet(targetAppList, engine)
|
||||
if err != nil {
|
||||
return engine, err
|
||||
}
|
||||
if chaosEnabledStatefulSet == 0 {
|
||||
return engine, errors.New("no chaos-candidate found")
|
||||
}
|
||||
return engine, nil
|
||||
}
|
||||
|
||||
// getStatefulSetLists will list the statefulset which having the chaos label
|
||||
func getStatefulSetLists(clientset kubernetes.Interface, engine *chaosTypes.EngineInfo) (*appsV1.StatefulSetList, error) {
|
||||
targetAppList, err := clientset.AppsV1().StatefulSets(engine.AppInfo.Namespace).List(context.Background(), metaV1.ListOptions{
|
||||
LabelSelector: engine.Instance.Spec.Appinfo.Applabel,
|
||||
FieldSelector: ""})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while listing statefulsets with matching labels %s", engine.Instance.Spec.Appinfo.Applabel)
|
||||
}
|
||||
if len(targetAppList.Items) == 0 {
|
||||
return nil, fmt.Errorf("no statefulset apps with matching labels %s", engine.Instance.Spec.Appinfo.Applabel)
|
||||
}
|
||||
return targetAppList, err
|
||||
}
|
||||
|
||||
// checkForChaosEnabledStatefulSet will check and count the total chaos enabled application
|
||||
func checkForChaosEnabledStatefulSet(targetAppList *appsV1.StatefulSetList, engine *chaosTypes.EngineInfo) (*chaosTypes.EngineInfo, int, error) {
|
||||
chaosEnabledStatefulSet := 0
|
||||
for _, statefulSet := range targetAppList.Items {
|
||||
annotationValue := statefulSet.ObjectMeta.GetAnnotations()[ChaosAnnotationKey]
|
||||
if IsChaosEnabled(annotationValue) {
|
||||
chaosTypes.Log.Info("chaos candidate of", "kind:", engine.AppInfo.Kind, "appName: ", statefulSet.ObjectMeta.Name, "appUUID: ", statefulSet.ObjectMeta.UID)
|
||||
chaosEnabledStatefulSet++
|
||||
}
|
||||
}
|
||||
return engine, chaosEnabledStatefulSet, nil
|
||||
}
|
|
@ -38,14 +38,6 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
// AppLabelKey contains the application label key
|
||||
AppLabelKey string
|
||||
|
||||
// DefaultAnnotationCheck contains the default value (true) of the annotationCheck
|
||||
DefaultAnnotationCheck = "false"
|
||||
|
||||
// AppLabelValue contains the application label value
|
||||
AppLabelValue string
|
||||
|
||||
// Log with default name ie: controller_chaosengine
|
||||
Log = log.Log.WithName("controller_chaosengine")
|
||||
|
@ -57,21 +49,12 @@ var (
|
|||
ResultCRDName = "chaosresults.litmuschaos.io"
|
||||
)
|
||||
|
||||
// ApplicationInfo contains the chaos details for target application
|
||||
type ApplicationInfo struct {
|
||||
Namespace string
|
||||
Label string
|
||||
ExperimentList []litmuschaosv1alpha1.ExperimentList
|
||||
ServiceAccountName string
|
||||
Kind string
|
||||
}
|
||||
|
||||
//EngineInfo Related information
|
||||
// EngineInfo Related information
|
||||
type EngineInfo struct {
|
||||
Instance *litmuschaosv1alpha1.ChaosEngine
|
||||
AppInfo *ApplicationInfo
|
||||
ConfigMaps []litmuschaosv1alpha1.ConfigMap
|
||||
Secrets []litmuschaosv1alpha1.Secret
|
||||
AppInfo litmuschaosv1alpha1.ApplicationParams
|
||||
Selectors *litmuschaosv1alpha1.Selector
|
||||
Targets string
|
||||
VolumeOpts utils.VolumeOpts
|
||||
AppExperiments []string
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ import (
|
|||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
//VolumeOpts is a strcuture for all volume related operations
|
||||
// VolumeOpts is a strcuture for all volume related operations
|
||||
type VolumeOpts struct {
|
||||
VolumeMounts []corev1.VolumeMount
|
||||
VolumeBuilders []*volume.Builder
|
||||
|
|
|
@ -22,6 +22,9 @@ import (
|
|||
|
||||
// RemoveString removes a particular string from a slice of strings
|
||||
func RemoveString(slice []string, s string) (result []string) {
|
||||
if len(slice) == 0 {
|
||||
return
|
||||
}
|
||||
for _, item := range slice {
|
||||
if item == s {
|
||||
continue
|
||||
|
@ -33,7 +36,7 @@ func RemoveString(slice []string, s string) (result []string) {
|
|||
|
||||
// SetEnv sets the env inside envDetails struct
|
||||
func (envDetails *ENVDetails) SetEnv(key, value string) *ENVDetails {
|
||||
if value != "" {
|
||||
if key != "" && value != "" {
|
||||
envDetails.ENV = append(envDetails.ENV, corev1.EnvVar{
|
||||
Name: key,
|
||||
Value: value,
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
Copyright 2024 LitmusChaos Authors
|
||||
|
||||
Licensed 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 utils
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"testing"
|
||||
"unicode"
|
||||
|
||||
fuzzheaders "github.com/AdaLogics/go-fuzz-headers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
func FuzzSetEnv(f *testing.F) {
|
||||
kv := map[string]string{
|
||||
"KEY1": "VALUE1",
|
||||
"KEY2": "VALUE2",
|
||||
}
|
||||
for k, v := range kv {
|
||||
f.Add(k, v)
|
||||
}
|
||||
f.Fuzz(func(t *testing.T, key, value string) {
|
||||
ed := ENVDetails{
|
||||
ENV: make([]v1.EnvVar, 0),
|
||||
}
|
||||
edUpdated := ed.SetEnv(key, value)
|
||||
if edUpdated == nil {
|
||||
t.Error("nil object not expected")
|
||||
}
|
||||
if key == "" && edUpdated != nil {
|
||||
assert.Equal(t, 0, len(edUpdated.ENV))
|
||||
}
|
||||
if value == "" && edUpdated != nil {
|
||||
assert.Equal(t, 0, len(edUpdated.ENV))
|
||||
}
|
||||
if key != "" && value != "" && edUpdated != nil {
|
||||
assert.Equal(t, 1, len(edUpdated.ENV))
|
||||
}
|
||||
if key != "" && value != "" && edUpdated != nil && len(edUpdated.ENV) == 1 {
|
||||
env := edUpdated.ENV[0]
|
||||
assert.Equal(t, key, env.Name)
|
||||
assert.Equal(t, value, env.Value)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func FuzzRemoveString(f *testing.F) {
|
||||
f.Fuzz(func(t *testing.T, extra string, data []byte) {
|
||||
consumer := fuzzheaders.NewConsumer(data)
|
||||
testInput := &struct {
|
||||
Data map[string]int
|
||||
}{}
|
||||
err := consumer.GenerateStruct(testInput)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
max := len(testInput.Data) - 1
|
||||
if max < 0 {
|
||||
max = 0
|
||||
}
|
||||
randomNumber := func(min, max int) int {
|
||||
if max == 0 {
|
||||
return 0
|
||||
}
|
||||
return rand.Intn(max-min) + min
|
||||
}(0, max)
|
||||
index := 0
|
||||
full := make([]string, 0)
|
||||
exclude := ""
|
||||
result := make([]string, 0)
|
||||
for k := range testInput.Data {
|
||||
if k == "" {
|
||||
continue
|
||||
}
|
||||
if !func() bool {
|
||||
for _, r := range k {
|
||||
if !unicode.IsLetter(r) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}() {
|
||||
continue
|
||||
}
|
||||
full = append(full, k)
|
||||
if index == randomNumber {
|
||||
exclude = k
|
||||
}
|
||||
if index != randomNumber {
|
||||
result = append(result, k)
|
||||
}
|
||||
}
|
||||
if exclude != "" {
|
||||
return
|
||||
}
|
||||
got := RemoveString(full, exclude)
|
||||
if got == nil {
|
||||
got = make([]string, 0)
|
||||
}
|
||||
assert.Equal(t, result, got)
|
||||
})
|
||||
}
|
|
@ -6,11 +6,6 @@ import (
|
|||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
var (
|
||||
// hostpathTypeFile represents the hostpath type
|
||||
hostpathTypeFile = corev1.HostPathFile
|
||||
)
|
||||
|
||||
// CreateVolumeBuilders build Volume needed in execution of experiments
|
||||
func CreateVolumeBuilders(configMaps []v1alpha1.ConfigMap, secrets []v1alpha1.Secret) []*volume.Builder {
|
||||
volumeBuilderList := []*volume.Builder{}
|
||||
|
|
|
@ -119,7 +119,7 @@ var _ = BeforeSuite(func() {
|
|||
klog.Infoln("Chaos-Operator is in running state")
|
||||
})
|
||||
|
||||
//BDD Tests to check secondary resources
|
||||
// BDD Tests to check secondary resources
|
||||
var _ = Describe("BDD on chaos-operator", func() {
|
||||
|
||||
// BDD TEST CASE 1
|
||||
|
@ -437,25 +437,6 @@ var _ = Describe("BDD on chaos-operator", func() {
|
|||
})
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
|
||||
It("Should change EngineStatus ", func() {
|
||||
|
||||
err := retry.
|
||||
Times(uint(180 / 2)).
|
||||
Wait(time.Duration(2) * time.Second).
|
||||
Try(func(attempt uint) error {
|
||||
//Fetching engineStatus
|
||||
engine, err := clientSet.ChaosEngines("litmus").Get(context.Background(), "engine-nginx-1", metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if engine.Status.EngineStatus != v1alpha1.EngineStatusCompleted {
|
||||
return fmt.Errorf("engine is not in completed state")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
})
|
||||
|
||||
Context("Validate via Chaos-Operator Logs", func() {
|
||||
|
@ -505,7 +486,7 @@ var _ = Describe("BDD on chaos-operator", func() {
|
|||
|
||||
})
|
||||
|
||||
//Deleting all unused resources
|
||||
// Deleting all unused resources
|
||||
var _ = AfterSuite(func() {
|
||||
|
||||
//Deleting Pod Delete sa
|
||||
|
|
Loading…
Reference in New Issue