From 7e04ebbcfddf7458124d0cbafd26cff0ff1346e0 Mon Sep 17 00:00:00 2001 From: OUM NIVRATHI KALE Date: Tue, 15 Feb 2022 14:24:46 +0530 Subject: [PATCH] Adding aws-az-experiment, Disable availability zones for load-balancer (#36) * adding aws-az-experiment Signed-off-by: Oum Kale * updating az experiment envs Signed-off-by: Oum Kale * initialise the chaosdetails using types Signed-off-by: Oum Kale --- bin/experiment/experiment.py | 3 + chaosLib/litmus/aws_az_chaos/__init__.py | 0 chaosLib/litmus/aws_az_chaos/lib/__init__.py | 0 .../litmus/aws_az_chaos/lib/aws_az_chaos.py | 145 ++++++++++++++++++ experiments/aws_az/__init__.py | 0 experiments/aws_az/aws_az_chaos/__init__.py | 0 .../aws_az_chaos/experiment/__init__.py | 0 .../aws_az_chaos/experiment/aws_az_chaos.py | 129 ++++++++++++++++ experiments/aws_az/aws_az_chaos/test/test.yml | 64 ++++++++ pkg/aws_az/__init__.py | 0 pkg/aws_az/environment/__init__.py | 0 pkg/aws_az/environment/environment.py | 45 ++++++ pkg/aws_az/types/__init__.py | 0 pkg/aws_az/types/types.py | 26 ++++ pkg/aws_status/__init__.py | 0 pkg/aws_status/status.py | 48 ++++++ pkg/utils/client/client.py | 15 +- requirements.txt | 1 + setup.py | 9 ++ 19 files changed, 481 insertions(+), 4 deletions(-) create mode 100644 chaosLib/litmus/aws_az_chaos/__init__.py create mode 100644 chaosLib/litmus/aws_az_chaos/lib/__init__.py create mode 100644 chaosLib/litmus/aws_az_chaos/lib/aws_az_chaos.py create mode 100644 experiments/aws_az/__init__.py create mode 100644 experiments/aws_az/aws_az_chaos/__init__.py create mode 100644 experiments/aws_az/aws_az_chaos/experiment/__init__.py create mode 100644 experiments/aws_az/aws_az_chaos/experiment/aws_az_chaos.py create mode 100644 experiments/aws_az/aws_az_chaos/test/test.yml create mode 100644 pkg/aws_az/__init__.py create mode 100644 pkg/aws_az/environment/__init__.py create mode 100644 pkg/aws_az/environment/environment.py create mode 100644 pkg/aws_az/types/__init__.py create mode 100644 pkg/aws_az/types/types.py create mode 100644 pkg/aws_status/__init__.py create mode 100644 pkg/aws_status/status.py diff --git a/bin/experiment/experiment.py b/bin/experiment/experiment.py index bedeef0..701f20d 100755 --- a/bin/experiment/experiment.py +++ b/bin/experiment/experiment.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 +import experiments.aws_az.aws_az_chaos.experiment.aws_az_chaos as aws_az_chaos import experiments.generic.pod_delete.experiment.pod_delete as pod_delete import argparse import logging @@ -23,6 +24,8 @@ def main(): # invoke the corresponding experiment based on the the (-name) flag if args.name == "pod-delete": pod_delete.PodDelete(clients) + elif args.name == "aws-az-chaos": + aws_az_chaos.AwsAzExperiment(clients) else: logging.error("Unsupported -name %s, please provide the correct value of -name args", args.name) return diff --git a/chaosLib/litmus/aws_az_chaos/__init__.py b/chaosLib/litmus/aws_az_chaos/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/chaosLib/litmus/aws_az_chaos/lib/__init__.py b/chaosLib/litmus/aws_az_chaos/lib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/chaosLib/litmus/aws_az_chaos/lib/aws_az_chaos.py b/chaosLib/litmus/aws_az_chaos/lib/aws_az_chaos.py new file mode 100644 index 0000000..8230035 --- /dev/null +++ b/chaosLib/litmus/aws_az_chaos/lib/aws_az_chaos.py @@ -0,0 +1,145 @@ + +import pkg.utils.common.common as common +import pkg.types.types as types +import pkg.events.events as events +import logging +from datetime import datetime +import pkg.maths.maths as maths + +#PrepareAWSAZExperiment contains the prepration steps before chaos injection +def PrepareAWSAZExperiment(experimentsDetails , resultDetails, eventsDetails, chaosDetails, clients, statusAws): + + # Waiting for the ramp time before chaos injection + if experimentsDetails.RampTime != 0 : + logging.info("[Ramp]: Waiting for the %s ramp time before injecting chaos",experimentsDetails.RampTime) + common.WaitForDuration(experimentsDetails.RampTime) + + # mode for chaos injection + if experimentsDetails.Sequence.lower() == "serial": + err = injectChaosInSerialMode(experimentsDetails, chaosDetails, eventsDetails, resultDetails, clients, statusAws) + if err != None: + return err + elif experimentsDetails.Sequence.lower() == "parallel": + err = injectChaosInParallelMode(experimentsDetails, chaosDetails, eventsDetails, resultDetails, clients, statusAws) + if err != None: + return err + else: + return ValueError("{} sequence is not supported".format(experimentsDetails.Sequence)) + + # Waiting for the ramp time after chaos injection + if experimentsDetails.RampTime != 0 : + logging.info("[Ramp]: Waiting for the %s ramp time after injecting chaos",experimentsDetails.RampTime) + common.WaitForDuration(experimentsDetails.RampTime) + + return None + +# injectChaosInSerialMode disable the target available zone from loadbalancer in serial mode(one by one) +def injectChaosInSerialMode(experimentsDetails , chaosDetails , eventsDetails , resultDetails, clients, statusAws): + + #ChaosStartTimeStamp contains the start timestamp, when the chaos injection begin + ChaosStartTimeStamp = datetime.now() + duration = (datetime.now() - ChaosStartTimeStamp).seconds + + while duration < experimentsDetails.ChaosDuration: + + # Get the target available zones for the chaos execution + targetZones = experimentsDetails.LoadBalancerZones.split(",") + + logging.info("[Info]: Target available zone list, %s", targetZones) + + if experimentsDetails.EngineName != "" : + msg = "Injecting " + experimentsDetails.ExperimentName + " chaos on available zone" + types.SetEngineEventAttributes(eventsDetails, types.ChaosInject, msg, "Normal", chaosDetails) + events.GenerateEvents(eventsDetails, chaosDetails, "ChaosEngine", clients) + + # Detaching the target zones from loa balancer + for azone in targetZones: + + logging.info("[Info]: Detaching the following zone(s), Zone Name : %s", azone) + err = statusAws.detachAZfromLB(experimentsDetails, azone) + if err != None: + return err + if chaosDetails.Randomness: + err = common.RandomInterval(experimentsDetails.ChaosInterval) + if err != None: + return err + else: + #Waiting for the chaos interval after chaos injection + if experimentsDetails.ChaosInterval != "": + logging.info("[Wait]: Wait for the chaos interval %s",(experimentsDetails.ChaosInterval)) + waitTime = maths.atoi(experimentsDetails.ChaosInterval) + common.WaitForDuration(waitTime) + + # Attaching the target available zone after the chaos injection + logging.info("[Status]: Attach the available zone back to load balancer") + err = statusAws.attachAZtoLB(experimentsDetails, azone) + if err != None: + return err + + #Verify the status of available zone after the chaos injection + logging.info("[Status]: Checking AWS load balancer's AZ status") + err = statusAws.CheckAWSStatus(experimentsDetails) + if err != None: + return err + + duration = (datetime.now() - ChaosStartTimeStamp).seconds + + logging.info("[Completion]: %s chaos is done",(experimentsDetails.ExperimentName)) + + return None + +# injectChaosInParallelMode disable the target available zone from loadbalancer in parallel mode (all at once) +def injectChaosInParallelMode(experimentsDetails , chaosDetails , eventsDetails , resultDetails, clients, statusAws): + + + #ChaosStartTimeStamp contains the start timestamp, when the chaos injection begin + ChaosStartTimeStamp = datetime.now() + duration = (datetime.now() - ChaosStartTimeStamp).seconds + + while duration < experimentsDetails.ChaosDuration: + + # Get the target available zone details for the chaos execution + targetZones = experimentsDetails.LoadBalancerZones.split(",") + logging.info("[Info]: Target available zone list, %s", targetZones) + + if experimentsDetails.EngineName != "" : + msg = "Injecting " + experimentsDetails.ExperimentName + " chaos on available zone" + types.SetEngineEventAttributes(eventsDetails, types.ChaosInject, msg, "Normal", chaosDetails) + events.GenerateEvents(eventsDetails, chaosDetails, "ChaosEngine",clients) + + # Detaching the target zones from loa balancer + for azone in targetZones: + logging.info("[Info]: Detaching the following zone(s), Zone Name %s", azone) + err = statusAws.detachAZfromLB(experimentsDetails, azone) + if err != None: + return err + + if chaosDetails.Randomness: + err = common.RandomInterval(experimentsDetails.ChaosInterval) + if err != None: + return err + else: + #Waiting for the chaos interval after chaos injection + if experimentsDetails.ChaosInterval != "" : + logging.info("[Wait]: Wait for the chaos interval %s", experimentsDetails.ChaosInterval) + waitTime = maths.atoi(experimentsDetails.ChaosInterval) + common.WaitForDuration(waitTime) + + # Attaching the target available zone after the chaos injection + logging.info("[Status]: Attach the available zone back to load balancer") + for azone in targetZones: + err = statusAws.attachAZtoLB(experimentsDetails, azone) + if err != None: + return err + + #Verify the status of available zone after the chaos injection + logging.info("[Status]: Checking AWS load balancer's AZ status") + err = statusAws.CheckAWSStatus(experimentsDetails) + if err != None: + return err + + duration = (datetime.now() - ChaosStartTimeStamp).seconds + + logging.info("[Completion]: %s chaos is done",(experimentsDetails.ExperimentName)) + + return None diff --git a/experiments/aws_az/__init__.py b/experiments/aws_az/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/experiments/aws_az/aws_az_chaos/__init__.py b/experiments/aws_az/aws_az_chaos/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/experiments/aws_az/aws_az_chaos/experiment/__init__.py b/experiments/aws_az/aws_az_chaos/experiment/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/experiments/aws_az/aws_az_chaos/experiment/aws_az_chaos.py b/experiments/aws_az/aws_az_chaos/experiment/aws_az_chaos.py new file mode 100644 index 0000000..45f494b --- /dev/null +++ b/experiments/aws_az/aws_az_chaos/experiment/aws_az_chaos.py @@ -0,0 +1,129 @@ +import pkg.types.types as types +import pkg.aws_az.types.types as experimentDetails +import pkg.aws_az.environment.environment as experimentEnv +import pkg.events.events as events +import logging +import chaosLib.litmus.aws_az_chaos.lib.aws_az_chaos as litmusLIB +import pkg.result.chaosresult as chaosResults +import pkg.utils.common.common as common +import pkg.aws_status.status as awsStatus + +# AwsAzExperiment contains steps to inject chaos +def AwsAzExperiment(clients): + + # Initialising expermentDetails, resultDetails, eventsDetails, chaosDetails, status and result objects + experimentsDetails = experimentDetails.ExperimentDetails() + resultDetails = types.ResultDetails() + eventsDetails = types.EventDetails() + chaosDetails = types.ChaosDetails() + result = chaosResults.ChaosResults() + statusAws = awsStatus.AWS_AZ() + + #Fetching all the ENV passed from the runner pod + experimentEnv.GetENV(experimentsDetails) + + logging.info("[PreReq]: Initialise Chaos Variables for the %s experiment", experimentsDetails.ExperimentName) + + # Intialise the chaos attributes + experimentEnv.InitialiseChaosVariables(chaosDetails, experimentsDetails) + + # Intialise Chaos Result Parameters + types.SetResultAttributes(resultDetails, chaosDetails) + + #Updating the chaos result in the beginning of experiment + logging.info("[PreReq]: Updating the chaos result of %s experiment (SOT)",(experimentsDetails.ExperimentName)) + err = result.ChaosResult(chaosDetails, resultDetails, "SOT", clients) + if err != None: + logging.error("Unable to Create the Chaos Result, err: %s",(err)) + failStep = "Updating the chaos result of aws-az-chaos experiment (SOT)" + result.RecordAfterFailure(chaosDetails, resultDetails, failStep, eventsDetails, clients) + return + + # Set the chaos result uid + result.SetResultUID(resultDetails, chaosDetails, clients) + + # generating the event in chaosresult to marked the verdict as awaited + msg = "Experiment " + experimentsDetails.ExperimentName + ", Result Awaited" + types.SetResultEventAttributes(eventsDetails, types.AwaitedVerdict, msg, "Normal", resultDetails) + events.GenerateEvents(eventsDetails, chaosDetails, "ChaosResult", clients) + + # DISPLAY THE LOADBALANCER INFORMATION + logging.info("[Info]: The application information is as follows LoadBalancer Name=%s, LoadBalancer Zones=%s, Ramp Time=%s",experimentsDetails.LoadBalancerName,experimentsDetails.LoadBalancerZones,experimentsDetails.RampTime) + + # Calling AbortWatcher, it will continuously watch for the abort signal and generate the required and result + common.AbortWatcher(experimentsDetails.ExperimentName, resultDetails, chaosDetails, eventsDetails, clients) + + # PRE-CHAOS APPLICATION STATUS CHECK + logging.info("[Status]: Verify that the AUT (Application Under Test) is running (pre-chaos)") + err = statusAws.CheckAWSStatus(experimentsDetails) + if err != None: + logging.error("Target available zone status check failed, err: %s", err) + failStep = "Verify that the AUT (Application Under Test) is running (pre-chaos)" + result.RecordAfterFailure(chaosDetails, resultDetails, failStep, eventsDetails, clients) + return + + if experimentsDetails.EngineName != "": + # marking AUT as running, as we already checked the status of application under test + msg = "AUT: Running" + # generating the for the pre-chaos check + types.SetEngineEventAttributes(eventsDetails, types.PreChaosCheck, msg, "Normal", chaosDetails) + events.GenerateEvents(eventsDetails, chaosDetails, "ChaosEngine", clients) + + # Including the litmus lib for aws-az-chaos + if experimentsDetails.ChaosLib == "litmus" : + err = litmusLIB.PrepareAWSAZExperiment(experimentsDetails, resultDetails, eventsDetails, chaosDetails, clients, statusAws) + if err != None: + logging.error("Chaos injection failed, err: %s",(err)) + failStep = "failed in chaos injection phase" + result.RecordAfterFailure(chaosDetails, resultDetails, failStep, eventsDetails, clients) + return + + else: + logging.info("[Invalid]: Please Provide the correct LIB") + failStep = "no match found for specified lib" + result.RecordAfterFailure(chaosDetails, resultDetails, failStep, eventsDetails, clients) + return + + logging.info("[Confirmation]: %s chaos has been injected successfully", experimentsDetails.ExperimentName) + resultDetails.Verdict = "Pass" + + # POST-CHAOS APPLICATION STATUS CHECK + logging.info("[Status]: Verify that the AUT (Application Under Test) is running (post-chaos)") + err = statusAws.CheckAWSStatus(experimentsDetails) + if err != None: + logging.error("Target aws instance status check failed, err: %s", err) + failStep = "Verify that the AUT (Application Under Test) is running (post-chaos)" + result.RecordAfterFailure(chaosDetails, resultDetails, failStep, eventsDetails, clients) + return + + + if experimentsDetails.EngineName != "" : + # marking AUT as running, as we already checked the status of application under test + msg = "AUT: Running" + + # generating post chaos event + types.SetEngineEventAttributes(eventsDetails, types.PostChaosCheck, msg, "Normal", chaosDetails) + events.GenerateEvents(eventsDetails, chaosDetails, "ChaosEngine", clients) + + + #Updating the chaosResult in the end of experiment + logging.info("[The End]: Updating the chaos result of %s experiment (EOT)", experimentsDetails.ExperimentName) + err = result.ChaosResult(chaosDetails, resultDetails, "EOT", clients) + if err != None: + logging.error("Unable to Update the Chaos Result, err: %s", err) + return + + # generating the event in chaosresult to marked the verdict as pass/fail + msg = "Experiment " + experimentsDetails.ExperimentName + ", Result " + resultDetails.Verdict + reason = types.PassVerdict + eventType = "Normal" + if resultDetails.Verdict != "Pass": + reason = types.FailVerdict + eventType = "Warning" + + types.SetResultEventAttributes(eventsDetails, reason, msg, eventType, resultDetails) + events.GenerateEvents(eventsDetails, chaosDetails, "ChaosResult", clients) + if experimentsDetails.EngineName != "": + msg = experimentsDetails.ExperimentName + " experiment has been " + resultDetails.Verdict + "ed" + types.SetEngineEventAttributes(eventsDetails, types.Summary, msg, "Normal", chaosDetails) + events.GenerateEvents(eventsDetails, chaosDetails, "ChaosEngine", clients) \ No newline at end of file diff --git a/experiments/aws_az/aws_az_chaos/test/test.yml b/experiments/aws_az/aws_az_chaos/test/test.yml new file mode 100644 index 0000000..af93282 --- /dev/null +++ b/experiments/aws_az/aws_az_chaos/test/test.yml @@ -0,0 +1,64 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: litmus-experiment +spec: + replicas: 1 + selector: + matchLabels: + app: litmus-experiment + template: + metadata: + labels: + app: litmus-experiment + spec: + serviceAccountName: aws_az_chaos-sa + containers: + - name: gotest + image: busybox + command: + - sleep + - "3600" + env: + - name: LOAD_BALANCER_NAME + value: '' + + - name: LOAD_BALANCER_ZONES + value: '' + + - name: LOAD_BALANCERNAME_ARN + value: '' + + - name: AWS_SHARED_CREDENTIALS_FILE + value: "" + + - name: TOTAL_CHAOS_DURATION + value: '' + + - name: AWS_REGIONS + value: "" + + ## Period to wait before injection of chaos in sec + - name: RAMP_TIME + value: '' + + ## env var that describes the library used to execute the chaos + ## default: litmus. Supported values: litmus, powerfulseal, chaoskube + - name: LIB + value: '' + + # provide the chaos namespace + - name: CHAOS_NAMESPACE + value: '' + + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + + - name: CHAOS_SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + diff --git a/pkg/aws_az/__init__.py b/pkg/aws_az/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pkg/aws_az/environment/__init__.py b/pkg/aws_az/environment/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pkg/aws_az/environment/environment.py b/pkg/aws_az/environment/environment.py new file mode 100644 index 0000000..681c0fc --- /dev/null +++ b/pkg/aws_az/environment/environment.py @@ -0,0 +1,45 @@ + +import os +import pkg.types.types as types +import pkg.maths.maths as maths + +#GetENV fetches all the env variables from the runner pod +def GetENV(experimentDetails): + experimentDetails.ExperimentName = os.getenv("EXPERIMENT_NAME", "aws-az-chaos") + experimentDetails.ChaosNamespace = os.getenv("CHAOS_NAMESPACE", "") + experimentDetails.EngineName = os.getenv("CHAOSENGINE", "") + experimentDetails.ChaosDuration = maths.atoi(os.getenv("TOTAL_CHAOS_DURATION", "")) + experimentDetails.ChaosInterval = os.getenv("CHAOS_INTERVAL", "") + experimentDetails.RampTime = maths.atoi(os.getenv("RAMP_TIME", "")) + experimentDetails.ChaosLib = os.getenv("LIB", "litmus") + experimentDetails.ChaosUID = os.getenv("CHAOS_UID", "") + experimentDetails.InstanceID = os.getenv("INSTANCE_ID", "") + experimentDetails.ChaosPodName = os.getenv("POD_NAME", "") + experimentDetails.Delay = maths.atoi(os.getenv("STATUS_CHECK_DELAY", "2")) + experimentDetails.Timeout = maths.atoi(os.getenv("STATUS_CHECK_TIMEOUT", "180")) + experimentDetails.Sequence = os.getenv("SEQUENCE", "parallel") + experimentDetails.AWSRegion = os.getenv("AWS_DEFAULT_REGION", "") + experimentDetails.LoadBalancerName = os.getenv("LOAD_BALANCER_NAME", "") + experimentDetails.LoadBalancerZones = os.getenv("LOAD_BALANCER_ZONES", "") + experimentDetails.LoadBalancerNameARN = os.getenv("LOAD_BALANCERNAME_ARN", "na") + +#InitialiseChaosVariables initialise all the global variables +def InitialiseChaosVariables(chaosDetails, experimentDetails): + appDetails = types.AppDetails() + appDetails.AnnotationCheck = (os.getenv("ANNOTATION_CHECK", "false") == 'true') + appDetails.AnnotationKey = os.getenv("ANNOTATION_KEY", "litmuschaos.io/chaos") + appDetails.AnnotationValue = "true" + appDetails.Kind = experimentDetails.AppKind + appDetails.Label = experimentDetails.AppLabel + appDetails.Namespace = experimentDetails.AppNS + + chaosDetails.ChaosNamespace = experimentDetails.ChaosNamespace + chaosDetails.ChaosPodName = experimentDetails.ChaosPodName + chaosDetails.ChaosUID = experimentDetails.ChaosUID + chaosDetails.EngineName = experimentDetails.EngineName + chaosDetails.ExperimentName = experimentDetails.ExperimentName + chaosDetails.InstanceID = experimentDetails.InstanceID + chaosDetails.Timeout = experimentDetails.Timeout + chaosDetails.Delay = experimentDetails.Delay + chaosDetails.AppDetail = appDetails + chaosDetails.Randomness = (os.getenv("RANDOMNESS", "false") == 'true') diff --git a/pkg/aws_az/types/__init__.py b/pkg/aws_az/types/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pkg/aws_az/types/types.py b/pkg/aws_az/types/types.py new file mode 100644 index 0000000..f2a6088 --- /dev/null +++ b/pkg/aws_az/types/types.py @@ -0,0 +1,26 @@ +# ExperimentDetails is for collecting all the experiment-related details +class ExperimentDetails(object): + def __init__(self, ExperimentName=None, EngineName=None, ChaosDuration=None, ChaosInterval=None, RampTime=None, Force=None, ChaosLib=None, + AWSZones=None, AWSRegion=None, AppNS=None, AppLabel=None, AppKind=None, InstanceID=None, ChaosNamespace=None, ChaosPodName=None, Timeout=None, + Delay=None, LoadBalancerName= None, LIBImagePullPolicy=None, LoadBalancerNameARN=None, LoadBalancerZones=None, UID=None): + self.ExperimentName = ExperimentName + self.EngineName = EngineName + self.ChaosDuration = ChaosDuration + self.ChaosInterval = ChaosInterval + self.RampTime = RampTime + self.ChaosLib = ChaosLib + self.AppNS = AppNS + self.AppLabel = AppLabel + self.AppKind = AppKind + self.InstanceID = InstanceID + self.ChaosUID = UID + self.ChaosNamespace = ChaosNamespace + self.ChaosPodName = ChaosPodName + self.Timeout = Timeout + self.Delay = Delay + self.LIBImagePullPolicy = LIBImagePullPolicy + self.AWSRegion = AWSRegion + self.LoadBalancerName = LoadBalancerName + self.LoadBalancerZones = LoadBalancerZones + self.LoadBalancerNameARN = LoadBalancerNameARN + diff --git a/pkg/aws_status/__init__.py b/pkg/aws_status/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pkg/aws_status/status.py b/pkg/aws_status/status.py new file mode 100644 index 0000000..ba6e703 --- /dev/null +++ b/pkg/aws_status/status.py @@ -0,0 +1,48 @@ +import boto3, logging +import pkg.utils.client.client as client + +# AWS_AZ class is checking the status of LoadBalancer and availablity zone +class AWS_AZ(object): + def __init__(self, client=None): + self.clients = client + + # CheckAWSStatus checks target load balancer availability + def CheckAWSStatus(self, experimentsDetails): + + self.clients = client.AWSClient().clientElb + + if experimentsDetails.LoadBalancerName == "" or experimentsDetails.LoadBalancerZones == "" : + return ValueError("Provided LoadBalancer Name or LoadBalanerZoner are empty") + + try: + self.clients.describe_load_balancers()['LoadBalancerDescriptions'] + except Exception as exp: + return ValueError(exp) + logging.info("[Info]: LoadBalancer and Availablity of zone has been checked") + + # detachAZfromLB detaching availablity zone from load balancer + def detachAZfromLB(self, experimentsDetails, zone): + self.clients = client.AWSClient().clientElb + try: + self.clients.disable_availability_zones_for_load_balancer( + LoadBalancerName=experimentsDetails.LoadBalancerName, + AvailabilityZones=[ + zone, + ] + ) + + except (self.clients.exceptions.AccessPointNotFoundException, self.clients.exceptions.InvalidConfigurationRequestException) as exp: + return ValueError(exp) + + # attachAZtoLB attaching availablity zone from load balancer + def attachAZtoLB(self, experimentsDetails, zone): + self.clients = client.AWSClient().clientElb + try: + self.clients.enable_availability_zones_for_load_balancer( + LoadBalancerName=experimentsDetails.LoadBalancerName, + AvailabilityZones=[ + zone, + ] + ) + except (self.clients.exceptions.AccessPointNotFoundException, self.clients.exceptions.InvalidConfigurationRequestException) as exp: + return ValueError(exp) diff --git a/pkg/utils/client/client.py b/pkg/utils/client/client.py index 0cb9ece..f137c2c 100644 --- a/pkg/utils/client/client.py +++ b/pkg/utils/client/client.py @@ -1,7 +1,8 @@ -import os +import os, boto3 from kubernetes import client, config, dynamic from kubernetes.client import api_client + # Client Class is maintaining clients for k8s class K8sClient(object): def __init__(self, conf=None): @@ -9,6 +10,12 @@ def __init__(self, conf=None): self.clientDyn = dynamic.DynamicClient(api_client.ApiClient(configuration=conf)) self.clientApps = client.AppsV1Api(conf) +# AWSClient is maintaining clients for aws +class AWSClient(object): + def __init__(self): + self.clientElb = boto3.client('elb') + self.clientElbv2 = boto3.client('elbv2') + # Config maintain configuration for in and out cluster class Configuration(object): @@ -23,9 +30,9 @@ def get_config(self): if self.kubeconfig != "": configs = self.kubeconfig elif os.getenv('KUBERNETES_SERVICE_HOST'): - configs = config.load_incluster_config() + configs = config.load_incluster_config() else: - configs = config.load_kube_config() - + configs = config.load_kube_config() + self.configurations = configs return configs diff --git a/requirements.txt b/requirements.txt index abfa005..fe7b885 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,3 +14,4 @@ pyparsing==2.4.7 python-dateutil==2.8.1 pytz==2021.1 pytzdata==2020.1 +boto3==1.20.13 \ No newline at end of file diff --git a/setup.py b/setup.py index c1a2002..cdbaaf0 100644 --- a/setup.py +++ b/setup.py @@ -69,6 +69,15 @@ def get_version_from_package() -> str: 'experiments', 'experiments/generic', 'experiments/generic/pod_delete', + 'chaosLib/litmus/aws_az_chaos', + 'chaosLib/litmus/aws_az_chaos/lib', + 'pkg/aws_az', + 'pkg/aws_az/environment', + 'pkg/aws_az/types', + 'pkg/aws_status', + 'experiments/aws_az', + 'experiments/aws_az/aws_az_chaos', + 'experiments/aws_az/aws_az_chaos/experiment', 'experiments/generic/pod_delete/experiment', ] needs_pytest = set(['pytest', 'test']).intersection(sys.argv)