diff --git a/paasta_tools/contrib/delete_old_marathon_deployments.py b/paasta_tools/contrib/delete_old_marathon_deployments.py new file mode 100755 index 0000000000..07c3faa05f --- /dev/null +++ b/paasta_tools/contrib/delete_old_marathon_deployments.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python +# Copyright 2015 Yelp Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import argparse +import datetime +import logging + +import dateutil.parser +from dateutil import tz +from pytimeparse import timeparse + +from paasta_tools import marathon_tools + + +log = logging.getLogger('__main__') +logging.basicConfig() + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument('-a', '--age', dest='age', type=timedelta_type, default='1h', + help="Max age of a Marathon deployment before it is stopped." + "Any pytimeparse unit is supported") + parser.add_argument('-n', '--dry-run', action="store_true", + help="Don't actually stop any Marathon deployments") + parser.add_argument('-v', '--verbose', action='store_true') + options = parser.parse_args() + return options + + +def timedelta_type(value): + """Return the :class:`datetime.datetime.DateTime` for a time in the past. + :param value: a string containing a time format supported by :mod:`pytimeparse` + """ + if value is None: + return None + return datetime_seconds_ago(timeparse.timeparse(value)) + + +def datetime_seconds_ago(seconds): + return now() - datetime.timedelta(seconds=seconds) + + +def now(): + return datetime.datetime.now(tz.tzutc()) + + +def delete_deployment_if_too_old(client, deployment, max_date, dry_run): + started_at = dateutil.parser.parse(deployment.version) + age = now() - started_at + if started_at < max_date: + if dry_run is True: + log.warning("Would delete %s for %s as it is %s old" % (deployment.id, deployment.affected_apps[0], age)) + else: + log.warning("Deleting %s for %s as it is %s old" % (deployment.id, deployment.affected_apps[0], age)) + client.delete_deployment(deployment_id=deployment.id, force=True) + else: + if dry_run is True: + log.warning("NOT deleting %s for %s as it is %s old" % (deployment.id, deployment.affected_apps[0], age)) + + +def main(): + args = parse_args() + + config = marathon_tools.load_marathon_config() + client = marathon_tools.get_marathon_client(config.get_url(), config.get_username(), config.get_password()) + + for deployment in client.list_deployments(): + delete_deployment_if_too_old( + client=client, + deployment=deployment, + max_date=args.age, + dry_run=args.dry_run, + ) + + +if __name__ == "__main__": + main() diff --git a/requirements.txt b/requirements.txt index cde8141f40..b553f2e501 100644 --- a/requirements.txt +++ b/requirements.txt @@ -32,6 +32,7 @@ pycrypto==2.6.1 pysensu-yelp==0.2.2 python-daemon==1.5.2 python-dateutil==2.4.2 +pytimeparse==1.1.5 pytz==2014.10 requests==2.6.2 requests-cache==0.4.10 diff --git a/setup.py b/setup.py index be7affa29b..5876c8f8fe 100644 --- a/setup.py +++ b/setup.py @@ -49,6 +49,7 @@ 'ordereddict >= 1.1', 'path.py >= 8.1', 'pysensu-yelp >= 0.2.2', + 'pytimeparse >= 1.1.0', 'python-dateutil >= 2.4.0', 'requests == 2.6.2', 'requests-cache >= 0.4.10, <= 0.5.0',