Skip to content

Commit 496be5f

Browse files
committed
feat(aws-az-chaos): refactor the aws-az-chaos experiment to use elbv2 in addition of elb classic from boto3. Also embed a fix for kubernetes dependency to upgrade it to a newer version.
Signed-off-by: Guillaume R 63466144+Guigui0812@users.noreply.github.com
1 parent cb7980c commit 496be5f

File tree

8 files changed

+167
-65
lines changed

8 files changed

+167
-65
lines changed

chaosLib/litmus/aws_az_chaos/lib/aws_az_chaos.py

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ def injectChaosInSerialMode(experimentsDetails , chaosDetails , eventsDetails ,
3939
#ChaosStartTimeStamp contains the start timestamp, when the chaos injection begin
4040
ChaosStartTimeStamp = datetime.now()
4141
duration = (datetime.now() - ChaosStartTimeStamp).seconds
42-
4342
while duration < experimentsDetails.ChaosDuration:
4443

4544
# Get the target available zones for the chaos execution
@@ -54,17 +53,23 @@ def injectChaosInSerialMode(experimentsDetails , chaosDetails , eventsDetails ,
5453

5554
# Detaching the target zones from loa balancer
5655
for azone in targetZones:
57-
5856
logging.info("[Info]: Detaching the following zone, Zone Name %s", azone)
5957
targetSubnet, err = statusAws.getTargetSubnet(experimentsDetails, azone)
60-
subnetList = list(targetSubnet.split(" "))
61-
if err != None:
62-
return err
63-
logging.info("[Info]: Detaching the following subnet, %s", subnetList)
64-
err = statusAws.detachSubnet(experimentsDetails, subnetList)
6558
if err != None:
6659
return err
6760

61+
if experimentsDetails.LoadBalancerVersion == "elb":
62+
subnetList = list(targetSubnet.split(" "))
63+
logging.info("[Info]: Detaching the following subnet, %s", subnetList)
64+
err = statusAws.detachSubnet(experimentsDetails, subnetList)
65+
if err != None:
66+
return err
67+
elif experimentsDetails.LoadBalancerVersion == "elbv2":
68+
logging.info("[Info]: Detaching the following subnet, %s", targetSubnet)
69+
err = statusAws.detachSubnetv2(experimentsDetails, targetSubnet)
70+
if err != None:
71+
return err
72+
6873
if chaosDetails.Randomness:
6974
err = common.RandomInterval(experimentsDetails.ChaosInterval)
7075
if err != None:
@@ -76,11 +81,21 @@ def injectChaosInSerialMode(experimentsDetails , chaosDetails , eventsDetails ,
7681
waitTime = maths.atoi(experimentsDetails.ChaosInterval)
7782
common.WaitForDuration(waitTime)
7883

79-
# Attaching the target available zone after the chaos injection
80-
logging.info("[Status]: Attach the available zone back to load balancer")
81-
err = statusAws.attachAZtoLB(experimentsDetails, azone)
82-
if err != None:
83-
return err
84+
if experimentsDetails.LoadBalancerVersion == "elb":
85+
86+
# Attaching the target available zone after the chaos injection
87+
logging.info("[Status]: Attach the available zone back to load balancer")
88+
err = statusAws.attachSubnet(experimentsDetails, subnetList)
89+
if err != None:
90+
return err
91+
92+
elif experimentsDetails.LoadBalancerVersion == "elbv2":
93+
94+
# Attaching again the target availability zone subnet after chaos injection
95+
logging.info("[Status]: Attach the available zone back to load balancer")
96+
err = statusAws.attachSubnetv2(experimentsDetails, targetSubnet)
97+
if err != None:
98+
return err
8499

85100
#Verify the status of available zone after the chaos injection
86101
logging.info("[Status]: Checking AWS load balancer's AZ status")

okteto.yml

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1-
name: litmus-experiment
2-
autocreate: true
3-
image: okteto/python:3
4-
command: bash
5-
volumes:
6-
- /root/.cache/pip
7-
sync:
8-
- .:/usr/src/app
9-
forward:
10-
- 8080:8080
11-
reverse:
12-
- 9000:9000
1+
dev:
2+
litmus-experiment:
3+
image: okteto/python:3
4+
command: bash -c "apt-get update && apt-get install -y build-essential python3-dev && pip install cython && bash"
5+
volumes:
6+
- /root/.cache/pip
7+
sync:
8+
- .:/usr/src/app
9+
reverse:
10+
- 9000:9000
11+
persistentVolume:
12+
enabled: true
13+
storageClass: gp3
14+
serviceAccount: "<your-litmus-sa-name>"
15+
environment:
16+
- <your-env-variables>

pkg/aws_az/environment/environment.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ def GetENV(experimentDetails):
1818
experimentDetails.Delay = maths.atoi(os.getenv("STATUS_CHECK_DELAY", "2"))
1919
experimentDetails.Timeout = maths.atoi(os.getenv("STATUS_CHECK_TIMEOUT", "180"))
2020
experimentDetails.Sequence = os.getenv("SEQUENCE", "parallel")
21-
experimentDetails.AWSRegion = os.getenv("AWS_DEFAULT_REGION", "")
21+
experimentDetails.AWSRegion = os.getenv("AWS_REGION", "")
2222
experimentDetails.LoadBalancerName = os.getenv("LOAD_BALANCER_NAME", "")
2323
experimentDetails.LoadBalancerZones = os.getenv("LOAD_BALANCER_ZONES", "")
2424
experimentDetails.LoadBalancerNameARN = os.getenv("LOAD_BALANCERNAME_ARN", "na")
25+
experimentDetails.LoadBalancerVersion = os.getenv("LOAD_BALANCER_VERSION", "elb")
2526

2627
#InitialiseChaosVariables initialise all the global variables
2728
def InitialiseChaosVariables(chaosDetails, experimentDetails):

pkg/aws_status/status.py

Lines changed: 106 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def CheckAWSStatus(self, experimentsDetails):
1414
self.clients = client.AWSClient().clientElb
1515

1616
if experimentsDetails.LoadBalancerName == "" or experimentsDetails.LoadBalancerZones == "" :
17-
return ValueError("Provided LoadBalancer Name or LoadBalanerZoner are empty")
17+
return ValueError("Provided LoadBalancer Name or LoadBalancerZoner are empty")
1818

1919
try:
2020
self.clients.describe_load_balancers()['LoadBalancerDescriptions']
@@ -23,36 +23,65 @@ def CheckAWSStatus(self, experimentsDetails):
2323
logging.info("[Info]: LoadBalancer and Availablity of zone has been checked")
2424

2525
def getSubnetFromVPC(self, experimentsDetails):
26-
client = boto3.client('elb')
27-
try:
28-
response = client.describe_load_balancers(
29-
LoadBalancerNames=[
30-
experimentsDetails.LoadBalancerName,
31-
]
32-
)
33-
return (response['LoadBalancerDescriptions'][0]['Subnets'])
34-
except (self.clients.exceptions.AccessPointNotFoundException, self.clients.exceptions.InvalidConfigurationRequestException) as exp:
35-
return ValueError(exp)
36-
37-
def getTargetSubnet(self, experimentsDetails, zone):
38-
client = boto3.client('ec2')
39-
try:
40-
lst=self.getSubnetFromVPC(experimentsDetails)
41-
i=0
42-
for i in range(len(lst)):
43-
response = client.describe_subnets(
44-
SubnetIds=[
45-
lst[i],
46-
],
26+
27+
if experimentsDetails.LoadBalancerVersion == "elb":
28+
29+
client = boto3.client('elb', region_name=experimentsDetails.AWSRegion)
30+
try:
31+
response = client.describe_load_balancers(
32+
LoadBalancerNames=[
33+
experimentsDetails.LoadBalancerName,
34+
]
4735
)
48-
if(response['Subnets'][0]['AvailabilityZone']) == zone:
49-
return lst[i], None
50-
except (self.clients.exceptions.AccessPointNotFoundException, self.clients.exceptions.InvalidConfigurationRequestException) as exp:
51-
return lst[i], ValueError(exp)
36+
return (response['LoadBalancerDescriptions'][0]['Subnets'])
37+
except (self.clients.exceptions.AccessPointNotFoundException, self.clients.exceptions.InvalidConfigurationRequestException) as exp:
38+
return ValueError(exp)
39+
40+
# Use dedicated client for elv2 when env var has been set
41+
elif experimentsDetails.LoadBalancerVersion == "elbv2":
5242

43+
client = boto3.client('elbv2', region_name=experimentsDetails.AWSRegion)
44+
try:
45+
response = client.describe_load_balancers(
46+
Names=[
47+
experimentsDetails.LoadBalancerName,
48+
]
49+
)
50+
return (response['LoadBalancers'][0]['AvailabilityZones'])
51+
except (self.clients.exceptions.AccessPointNotFoundException, self.clients.exceptions.InvalidConfigurationRequestException) as exp:
52+
return ValueError(exp)
5353

54+
def getTargetSubnet(self, experimentsDetails, zone):
55+
client = boto3.client('ec2', region_name=experimentsDetails.AWSRegion)
56+
if experimentsDetails.LoadBalancerVersion == "elb":
57+
58+
try:
59+
lst=self.getSubnetFromVPC(experimentsDetails)
60+
i=0
61+
for i in range(len(lst)):
62+
response = client.describe_subnets(
63+
SubnetIds=[
64+
lst[i],
65+
],
66+
)
67+
if(response['Subnets'][0]['AvailabilityZone']) == zone:
68+
return lst[i], None
69+
except (self.clients.exceptions.AccessPointNotFoundException, self.clients.exceptions.InvalidConfigurationRequestException) as exp:
70+
return lst[i], ValueError(exp)
71+
72+
# Specific section to deal with the output of the elv2 client
73+
elif experimentsDetails.LoadBalancerVersion == "elbv2":
74+
try:
75+
lst =self.getSubnetFromVPC(experimentsDetails)
76+
i=0
77+
for i in range(len(lst)):
78+
if (lst[i]['ZoneName']) == zone:
79+
return lst[i]['SubnetId'], None
80+
except (self.clients.exceptions.AccessPointNotFoundException, self.clients.exceptions.InvalidConfigurationRequestException) as exp:
81+
return lst[i], ValueError(exp)
82+
5483
def detachSubnet(self, experimentsDetails, subnet):
55-
client = boto3.client('elb')
84+
client = boto3.client('elb', region_name=experimentsDetails.AWSRegion)
5685
try:
5786
response = client.detach_load_balancer_from_subnets(
5887
LoadBalancerName=experimentsDetails.LoadBalancerName,
@@ -63,8 +92,33 @@ def detachSubnet(self, experimentsDetails, subnet):
6392
except (self.clients.exceptions.AccessPointNotFoundException, self.clients.exceptions.InvalidConfigurationRequestException) as exp:
6493
return ValueError(exp)
6594

95+
# Specific method to detach the subnet with elbv2 client
96+
def detachSubnetv2(self, experimentsDetails, subnet):
97+
client = boto3.client('elbv2', region_name=experimentsDetails.AWSRegion)
98+
try:
99+
100+
subnetsToKeep = []
101+
response = client.describe_load_balancers(
102+
Names=[
103+
experimentsDetails.LoadBalancerName,
104+
]
105+
)
106+
107+
# List subnet to keep that are currently attached to the LB
108+
for az in response['LoadBalancers'][0]['AvailabilityZones']:
109+
if az['SubnetId'] not in subnet:
110+
subnetsToKeep.append(az['SubnetId'])
111+
112+
response = client.set_subnets(
113+
LoadBalancerArn=response['LoadBalancers'][0]['LoadBalancerArn'],
114+
Subnets=subnetsToKeep
115+
)
116+
117+
except (self.clients.exceptions.AccessPointNotFoundException, self.clients.exceptions.InvalidConfigurationRequestException) as exp:
118+
return ValueError(exp)
119+
66120
def attachSubnet(self, experimentsDetails, subnet):
67-
client = boto3.client('elb')
121+
client = boto3.client('elb', region_name=experimentsDetails.AWSRegion)
68122
try:
69123
response = client.attach_load_balancer_to_subnets(
70124
LoadBalancerName=experimentsDetails.LoadBalancerName,
@@ -74,4 +128,27 @@ def attachSubnet(self, experimentsDetails, subnet):
74128
ValueError("[Error]: Fail to attach the target subnet %s", subnet)
75129
except (self.clients.exceptions.AccessPointNotFoundException, self.clients.exceptions.InvalidConfigurationRequestException) as exp:
76130
return ValueError(exp)
77-
131+
132+
# Specific method to attach the removed subnet with elbv2 client after Chaos
133+
def attachSubnetv2(self, experimentsDetails, subnet):
134+
client = boto3.client('elbv2', region_name=experimentsDetails.AWSRegion)
135+
try:
136+
137+
subnetsToKeep = [subnet]
138+
response = client.describe_load_balancers(
139+
Names=[
140+
experimentsDetails.LoadBalancerName,
141+
]
142+
)
143+
144+
for az in response['LoadBalancers'][0]['AvailabilityZones']:
145+
if az['SubnetId'] not in subnet:
146+
subnetsToKeep.append(az['SubnetId'])
147+
148+
response = client.set_subnets(
149+
LoadBalancerArn=response['LoadBalancers'][0]['LoadBalancerArn'],
150+
Subnets=subnetsToKeep
151+
)
152+
153+
except (self.clients.exceptions.AccessPointNotFoundException, self.clients.exceptions.InvalidConfigurationRequestException) as exp:
154+
return ValueError(exp)

pkg/events/events.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#CreateEvents create the events in the desired resource
77
def CreateEvents(eventsDetails , chaosDetails, kind, eventName, clients):
88

9-
event = client.V1Event(
9+
event = client.CoreV1Event(
1010
first_timestamp = datetime.now(pytz.utc),
1111
last_timestamp = datetime.now(pytz.utc),
1212
event_time = datetime.now(pytz.utc),
@@ -52,7 +52,7 @@ def GenerateEvents(eventsDetails, chaosDetails, kind, clients):
5252
return err
5353
elif kind == "ChaosEngine":
5454
eventName = eventsDetails.Reason + chaosDetails.ExperimentName + str(chaosDetails.ChaosUID)
55-
event = client.V1Event
55+
event = client.CoreV1Event
5656
try:
5757
event = clients.clientCoreV1.read_namespaced_event(name = eventName,namespace = chaosDetails.ChaosNamespace)
5858
except Exception as exp:

pkg/utils/client/client.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import os, boto3
22
from kubernetes import client, config, dynamic
33
from kubernetes.client import api_client
4-
4+
import pkg.aws_az.types.types as experimentDetails
5+
from botocore.config import Config
6+
import pkg.aws_az.environment.environment as experimentEnv
57

68
# Client Class is maintaining clients for k8s
79
class K8sClient(object):
@@ -12,9 +14,10 @@ def __init__(self, conf=None):
1214

1315
# AWSClient is maintaining clients for aws
1416
class AWSClient(object):
15-
def __init__(self):
16-
self.clientElb = boto3.client('elb')
17-
self.clientElbv2 = boto3.client('elbv2')
17+
def __init__(self, experimentsDetails):
18+
19+
self.clientElb = boto3.client('elb', region_name=experimentsDetails.AWSRegion)
20+
self.clientElbv2 = boto3.client('elbv2', region_name=experimentsDetails.AWSRegion)
1821

1922
# Config maintain configuration for in and out cluster
2023
class Configuration(object):

requirements.txt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
cachetools==4.2.2
2-
chaostoolkit-kubernetes==0.25.1
3-
chaostoolkit-lib==1.19.0
2+
chaostoolkit-lib==1.44.0
3+
chaostoolkit-kubernetes==0.29.0
44
dateparser==1.0.0
55
decorator==5.0.9
66
idna==2.10
77
Jinja2==2.11.3
8-
kubernetes==17.17.0
8+
kubernetes==34.1.0
99
protobuf==3.17.1
1010
py==1.10.0
1111
pyasn1==0.4.8
@@ -15,4 +15,6 @@ python-dateutil==2.8.1
1515
pytz==2021.1
1616
pytzdata==2020.1
1717
boto3==1.20.13
18-
markupsafe==2.0.1
18+
markupsafe==2.0.1
19+
setuptools==80.9.0
20+
legacy-cgi===2.6.4

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ def get_version_from_package() -> str:
102102
include_package_data=True,
103103
install_requires=install_require,
104104
setup_requires=pytest_runner,
105-
python_requires='>=3.5.*'
105+
python_requires='>=3.5'
106106
)
107107

108108

0 commit comments

Comments
 (0)