0

I have couple of methods inside a class that control a virtual machine life-cycle. Operations like start, stop, terminate, retire .. etc

The code for these methods is almost identical, for example:

def stop(self, instances):
    """
    Stop instance or a group of instances
    :param instances: List of instances
    :return:
    """
    try:
        response = self.ec2_client.stop_instances(InstanceIds=instances, DryRun=False)
        print(response)
    except ClientError as e:
        print(e)

    return response

def start(self, instances):
    """
    Start instance or a group of instances
    :param instances: List of instances
    :return:
    """
    try:
        response = self.ec2_client.start_instances(InstanceIds=instances, DryRun=False)
        print(response)
    except ClientError as e:
        print(e)

    return response

As you can see, the two methods are almost identical except for the API call to perform the required action (start_instances and stop_instance).

Is there is a way to write such methods or functions in general and prevent repeating code?

Thanks in advance.

P.S. I was thinking of decorators, instance functions, closures -- but just don't know how!


Below answers inspired me to the following solution:

    @staticmethod
def _request_action_method(action, instances):
    instance_ids = FleetManager._instance_to_str(instances)

    def _action_method():
        try:
            response = action(InstanceIds=instance_ids, DryRun=False)
            print(response)
        except ClientError as e:
            print(e)

    return _action_method

I could replace +50 lines of code with those few lines and it works :)

0

2 Answers 2

3

Make a function let's say

@staticmethod
def _request(method, instances):
 try:
    response = method(InstanceIds=instances, DryRun=False)
    print(response)
 except ClientError as e:
    print(e)
 return response

and call them

def stop(self, instances):
  self._request(self.ec2_client.stop_instances, instances)

def start(self, instances):
  self._request(self.ec2_client.start_instances, instances)
Sign up to request clarification or add additional context in comments.

Comments

1

You can store a map of of stop: {stop_instances, start: start_instances} and call a single function that does the rest. Use getattr to obtain the member from self.ec2_client by name, or just the whole method.

Pseudo code:

In __init__:

self.methodmap = {'start': self.ec2_client.start_instances,
                  'stop': self.ec2_client.stop_instances}

Then, for example:

def start(self, instances):
  return self.run('start', instances)

def run(self, command, instances):
  method = self.methodmap[command]
  try:
    response = method(InstanceIds=instances, DryRun=False)
    print(response)
  except ClientError as e:
    print (e)
  return response

Depending on how much flexibility you want, you don't have to define self.methodmap but can also pass the method direction in the invocation of self.run.

For extra magic (be careful!) you can auto-generate the start, stop etc. methods too, because they all follow the same pattern.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.