From 5cf42dbf2683f23063ad986f89c85336b83635d5 Mon Sep 17 00:00:00 2001 From: Rodrigue Date: Sat, 3 Feb 2018 23:02:58 +0100 Subject: [PATCH 1/5] Futurize python files --- amicleaner/cli.py | 46 ++++++++++++++++++---------------- amicleaner/core.py | 15 ++++++----- amicleaner/fetch.py | 6 +++-- amicleaner/resources/models.py | 14 +++++++---- amicleaner/utils.py | 23 +++++++++-------- tests/test_cli.py | 2 +- 6 files changed, 61 insertions(+), 45 deletions(-) diff --git a/amicleaner/cli.py b/amicleaner/cli.py index a3de5b0..38990a8 100755 --- a/amicleaner/cli.py +++ b/amicleaner/cli.py @@ -1,17 +1,21 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +from __future__ import print_function +from __future__ import absolute_import +from builtins import input +from builtins import object import sys from amicleaner import __version__ -from core import AMICleaner, OrphanSnapshotCleaner -from fetch import Fetcher -from resources.config import MAPPING_KEY, MAPPING_VALUES -from resources.config import TERM -from utils import Printer, parse_args +from .core import AMICleaner, OrphanSnapshotCleaner +from .fetch import Fetcher +from .resources.config import MAPPING_KEY, MAPPING_VALUES +from .resources.config import TERM +from .utils import Printer, parse_args -class App: +class App(object): def __init__(self, args): @@ -48,7 +52,7 @@ def fetch_candidates(self, available_amis=None, excluded_amis=None): candidates = [v for k, v - in available_amis.iteritems() + in available_amis.items() if k not in excluded_amis] return candidates @@ -74,7 +78,7 @@ def prepare_candidates(self, candidates_amis=None): candidates = [] report = dict() - for group_name, amis in mapped_amis.iteritems(): + for group_name, amis in mapped_amis.items(): group_name = group_name or "" if not group_name: @@ -96,16 +100,16 @@ def prepare_delete_amis(self, candidates, from_ids=False): failed = [] if from_ids: - print TERM.bold("\nCleaning from {} AMI id(s) ...".format( + print(TERM.bold("\nCleaning from {} AMI id(s) ...".format( len(candidates)) - ) + )) failed = AMICleaner().remove_amis_from_ids(candidates) else: - print TERM.bold("\nCleaning {} AMIs ...".format(len(candidates))) + print(TERM.bold("\nCleaning {} AMIs ...".format(len(candidates)))) failed = AMICleaner().remove_amis(candidates) if failed: - print TERM.red("\n{0} failed snapshots".format(len(failed))) + print(TERM.red("\n{0} failed snapshots".format(len(failed)))) Printer.print_failed_snapshots(failed) def clean_orphans(self): @@ -120,22 +124,22 @@ def clean_orphans(self): Printer.print_orphan_snapshots(snaps) - answer = raw_input( + answer = input( "Do you want to continue and remove {} orphan snapshots " "[y/N] ? : ".format(len(snaps))) confirm = (answer.lower() == "y") if confirm: - print "Removing orphan snapshots... " + print("Removing orphan snapshots... ") count = cleaner.clean(snaps) - print "\n{0} orphan snapshots successfully removed !".format(count) + print("\n{0} orphan snapshots successfully removed !".format(count)) def print_defaults(self): - print TERM.bold("\nDefault values : ==>") - print TERM.green("mapping_key : {0}".format(self.mapping_key)) - print TERM.green("mapping_values : {0}".format(self.mapping_values)) - print TERM.green("keep_previous : {0}".format(self.keep_previous)) + print(TERM.bold("\nDefault values : ==>")) + print(TERM.green("mapping_key : {0}".format(self.mapping_key))) + print(TERM.green("mapping_values : {0}".format(self.mapping_values))) + print(TERM.green("keep_previous : {0}".format(self.keep_previous))) @staticmethod def print_version(): @@ -152,7 +156,7 @@ def run_cli(self): # print defaults self.print_defaults() - print TERM.bold("\nRetrieving AMIs to clean ...") + print(TERM.bold("\nRetrieving AMIs to clean ...")) candidates = self.prepare_candidates() if not candidates: @@ -161,7 +165,7 @@ def run_cli(self): delete = False if not self.force_delete: - answer = raw_input( + answer = input( "Do you want to continue and remove {} AMIs " "[y/N] ? : ".format(len(candidates))) delete = (answer.lower() == "y") diff --git a/amicleaner/core.py b/amicleaner/core.py index 5d645bd..9e45467 100644 --- a/amicleaner/core.py +++ b/amicleaner/core.py @@ -1,12 +1,15 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +from __future__ import print_function +from __future__ import absolute_import +from builtins import object import boto3 from botocore.exceptions import ClientError -from resources.models import AMI +from .resources.models import AMI -class OrphanSnapshotCleaner: +class OrphanSnapshotCleaner(object): """ Finds and removes ebs snapshots left orphaned """ @@ -82,10 +85,10 @@ def clean(self, snapshots): return count def log(self, msg): - print msg + print(msg) -class AMICleaner: +class AMICleaner(object): def __init__(self, ec2=None): self.ec2 = ec2 or boto3.client('ec2') @@ -109,7 +112,7 @@ def remove_amis(self, amis): amis = amis or [] for ami in amis: self.ec2.deregister_image(ImageId=ami.id) - print "{0} deregistered".format(ami.id) + print("{0} deregistered".format(ami.id)) for block_device in ami.block_device_mappings: try: self.ec2.delete_snapshot( @@ -117,7 +120,7 @@ def remove_amis(self, amis): ) except ClientError: failed_snapshots.append(block_device.snapshot_id) - print "{0} deleted\n".format(block_device.snapshot_id) + print("{0} deleted\n".format(block_device.snapshot_id)) return failed_snapshots diff --git a/amicleaner/fetch.py b/amicleaner/fetch.py index f8cec9d..68dff74 100644 --- a/amicleaner/fetch.py +++ b/amicleaner/fetch.py @@ -1,11 +1,13 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +from __future__ import absolute_import +from builtins import object import boto3 -from resources.models import AMI +from .resources.models import AMI -class Fetcher: +class Fetcher(object): """ Fetches function for AMI candidates to deletion """ diff --git a/amicleaner/resources/models.py b/amicleaner/resources/models.py index f1aa25b..41070f7 100644 --- a/amicleaner/resources/models.py +++ b/amicleaner/resources/models.py @@ -2,7 +2,11 @@ # -*- coding: utf-8 -*- -class AMI: +from builtins import str +from builtins import object + + +class AMI(object): def __init__(self): self.id = None self.architecture = None @@ -52,7 +56,7 @@ def object_with_json(json): AWSBlockDevice.object_with_json(block_device) for block_device in json.get('BlockDeviceMappings', []) ] - o.block_device_mappings = filter(None, ebs_snapshots) + o.block_device_mappings = [f for f in ebs_snapshots if f] return o @@ -62,7 +66,7 @@ def __repr__(self): self.creation_date) -class AWSEC2Instance: +class AWSEC2Instance(object): def __init__(self): self.id = None self.name = None @@ -110,7 +114,7 @@ def object_with_json(json): return o -class AWSBlockDevice: +class AWSBlockDevice(object): def __init__(self): self.device_name = None self.snapshot_id = None @@ -146,7 +150,7 @@ def object_with_json(json): return o -class AWSTag: +class AWSTag(object): def __init__(self): self.key = None self.value = None diff --git a/amicleaner/utils.py b/amicleaner/utils.py index 829a04e..6ce53c7 100644 --- a/amicleaner/utils.py +++ b/amicleaner/utils.py @@ -1,14 +1,17 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +from __future__ import print_function +from __future__ import absolute_import +from builtins import object import argparse from prettytable import PrettyTable -from resources.config import KEEP_PREVIOUS +from .resources.config import KEEP_PREVIOUS -class Printer: +class Printer(object): """ Pretty table prints methods """ @staticmethod @@ -21,7 +24,7 @@ def print_report(candidates, full_report=False): groups_table = PrettyTable(["Group name", "candidates"]) - for group_name, amis in candidates.iteritems(): + for group_name, amis in candidates.items(): groups_table.add_row([group_name, len(amis)]) eligible_amis_table = PrettyTable( ["AMI ID", "AMI Name", "Creation Date"] @@ -33,11 +36,11 @@ def print_report(candidates, full_report=False): ami.creation_date ]) if full_report: - print group_name - print eligible_amis_table.get_string(sortby="AMI Name"), "\n\n" + print(group_name) + print(eligible_amis_table.get_string(sortby="AMI Name"), "\n\n") - print "\nAMIs to be removed:" - print groups_table.get_string(sortby="Group name") + print("\nAMIs to be removed:") + print(groups_table.get_string(sortby="Group name")) @staticmethod def print_failed_snapshots(snapshots): @@ -46,7 +49,7 @@ def print_failed_snapshots(snapshots): for snap in snapshots: snap_table.add_row([snap]) - print snap_table + print(snap_table) @staticmethod def print_orphan_snapshots(snapshots): @@ -55,7 +58,7 @@ def print_orphan_snapshots(snapshots): for snap in snapshots: snap_table.add_row([snap]) - print snap_table + print(snap_table) def parse_args(args): @@ -106,7 +109,7 @@ def parse_args(args): parsed_args = parser.parse_args(args) if parsed_args.mapping_key and not parsed_args.mapping_values: - print "missing mapping-values\n" + print("missing mapping-values\n") parser.print_help() return None diff --git a/tests/test_cli.py b/tests/test_cli.py index f8b425e..3cd11ae 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -41,7 +41,7 @@ def test_deletion(): # create amis images = [] - for i in xrange(5): + for i in range(5): image = ec2.create_image( InstanceId=instance.get("InstanceId"), Name="test-ami" From accc2a6f2dce46340f0e90f94b3507c888b2c846 Mon Sep 17 00:00:00 2001 From: Rodrigue Date: Sat, 3 Feb 2018 23:03:41 +0100 Subject: [PATCH 2/5] Raise 79 length constraint --- pytest.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/pytest.ini b/pytest.ini index b203d1b..605d1b5 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,3 +1,4 @@ [pytest] rootdir = tests addopts = --cov-report html --cov-fail-under 80 --cov . --pep8 +pep8maxlinelength = 120 From 6d0d370f762121466a22d07dcb8e2a0aac106b58 Mon Sep 17 00:00:00 2001 From: Rodrigue Date: Sat, 3 Feb 2018 23:04:36 +0100 Subject: [PATCH 3/5] Tests against python versions --- .travis.yml | 8 +++++++- Dockerfile-python3 | 13 +++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 Dockerfile-python3 diff --git a/.travis.yml b/.travis.yml index 318bf01..457ec88 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,13 @@ env: dist: trusty language: python -python: "2.7" +python: + - "2.6" + - "2.7" + - "3.3" + - "3.4" + - "3.5" + - "3.6" install: - pip install -r requirements_build.txt diff --git a/Dockerfile-python3 b/Dockerfile-python3 new file mode 100644 index 0000000..fbb3409 --- /dev/null +++ b/Dockerfile-python3 @@ -0,0 +1,13 @@ +FROM python:3.6 + +RUN apt-get update && apt-get install -y \ + vim \ + jq + +WORKDIR /aws-amicleaner + +ADD . . + +RUN python setup.py install + +CMD bash From 9138b537d9b59c6ac215823e42be414af47e4a05 Mon Sep 17 00:00:00 2001 From: Rodrigue Date: Sat, 3 Feb 2018 23:07:54 +0100 Subject: [PATCH 4/5] Update gitignore --- .gitignore | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/.gitignore b/.gitignore index 9ccd7b2..f40357b 100644 --- a/.gitignore +++ b/.gitignore @@ -38,48 +38,19 @@ pip-delete-this-directory.txt htmlcov/ .tox/ .coverage -.coverage.* .cache +.pytest_cache nosetests.xml coverage.xml *,cover .hypothesis/ -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py - -# Flask instance folder -instance/ - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - # PyBuilder target/ -# IPython Notebook -.ipynb_checkpoints # pyenv .python-version -# celery beat schedule file -celerybeat-schedule - # dotenv .env - -# Spyder project settings -.spyderproject - -# Vagrant -Vagrantfile -.vagrant/ From 52e8099310f556138c4c21d2d76fe62033701003 Mon Sep 17 00:00:00 2001 From: Rodrigue Date: Sat, 3 Feb 2018 23:51:58 +0100 Subject: [PATCH 5/5] Fix incompatible pytest setup in previous python versions --- .travis.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 457ec88..7c4b67c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,9 +5,6 @@ env: dist: trusty language: python python: - - "2.6" - - "2.7" - - "3.3" - "3.4" - "3.5" - "3.6" @@ -16,7 +13,7 @@ install: - pip install -r requirements_build.txt script: - - py.test + - py.test -v after_success: - codecov