0

I'm taking my first programming course so please pardon if questions are too naive. I'm using Python Boto3 module and 'Click' library to build a Command Line Interface that manages EC2 instances. Code:

@click.group()
@cli.group('instances')
def instances():
    pass
@instances.command('list')
@click.option('--project', default=None,help='List instances by project tag, e.g. -project = <project name>')
def list_instances(project):
    'List EC2 instances'
    instances = filter_project_instances(project)
    for i in instances:
            print(', '.join((
            i.id,
            i.instance_type,
        )))
        return

@cli.group('volumes')
#Details of this 'volumes' command are omitted for simplification 

Basically, 'Click' allows me to wrap my functions with commands (e.g. instances, volumes), subcommands(list) and option (--project). Such a command line: shotty.py instances list --project Valkyrie can list instances that are tagged with the name 'Valkyrie'

Now, I'm required to add an option to this command line to specify the AWS profile I wanna use to log in. The profile was created with 'aws configure --profile [profile name]' command (profile names can be Dan, Kyle, etc.):

shotty.py --profile [profile name] instances list

Initially, I hardcoded the profile name and used session and ec2 as global variables that any other functions can use.

import boto3
import botocore
import click

session = boto3.Session(profile_name='Dan')
ec2 = session.resource('ec2')

Though implementing the above requirement, based on 'Click' documents, I had to do the following to add such a '--profile' option:

@click.group()
@click.option('--profile', default=None,help='Select the AWS profile')
def cli(profile):
   session = boto3.Session(profile_name=profile)
   ec2 = session.resource('ec2')

But now, session and ec2 are not available to other functions any more. This cli() function is like an entry point of the script and is revoked in the main() function:

if __name__ == '__main__':
    cli()

My only approach I could think of was creating a separate function

  def session(profile):
        session = boto3.Session(profile_name=profile)
        ec2 = session.resource('ec2')
        return ec2

But now this brings another issue that I have to add profile as a parameter to all other functions, e.g.

def filter_project_instances(project, profile):
        'Filter EC2 instances'
        ec2 = session(profile)
        instances = ec2.instances.all()
        return instances

This means I have to define profile again somehow in this filter_project_instances function. It does not make much sense to me. Any help would be appreciated! Update: I had a look at the global keyword before posting but most searches told me that having global variable was mostly a sign of a bad design so I was thinking that I was lacking something pythonically to make it work here 😅

1 Answer 1

0

After experimenting, seemed like the most suitable solution is make my profile variable global by

@click.group()
@click.option('--profile', default = None, help='Select the AWS profile')
def cli(profile):
    "Shotty manages snapshots"
    session = boto3.Session(profile_name=profile)
    ec2_cli = session.resource('ec2')
    global ec2
    ec2 = ec2_cli

Though this approach is usually frowned upon, I've been struggling to encapsulate all related functions in a class as recommended by most people (How to share values between functions in Python?) This global variable solution in this case seems best as it involves least changes in code

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.