102 lines
3.9 KiB
Python
102 lines
3.9 KiB
Python
# Copyright (c) 2020 The ARA Records Ansible authors
|
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
# See https://github.com/ansible-community/ara/issues/26 for rationale on expiring
|
|
|
|
import logging
|
|
import os
|
|
import sys
|
|
from datetime import datetime, timedelta
|
|
|
|
from cliff.command import Command
|
|
|
|
from ara.cli.base import global_arguments
|
|
from ara.clients.utils import get_client
|
|
|
|
|
|
class ExpireObjects(Command):
|
|
""" Expires objects that have been in the running state for too long """
|
|
|
|
log = logging.getLogger(__name__)
|
|
expired = 0
|
|
|
|
def get_parser(self, prog_name):
|
|
parser = super(ExpireObjects, self).get_parser(prog_name)
|
|
parser = global_arguments(parser)
|
|
# fmt: off
|
|
parser.add_argument(
|
|
"--hours",
|
|
type=int,
|
|
default=24,
|
|
help="Expires objects that have been running state for this many hours (default: 24)"
|
|
)
|
|
parser.add_argument(
|
|
"--order",
|
|
metavar="<order>",
|
|
default="started",
|
|
help=(
|
|
"Orders objects by a field ('id', 'created', 'updated', 'started', 'ended')\n"
|
|
"Defaults to 'started' descending so the oldest objects would be expired first.\n"
|
|
"The order can be reversed by using '-': ara expire --order=-started"
|
|
),
|
|
)
|
|
parser.add_argument(
|
|
"--limit",
|
|
metavar="<limit>",
|
|
default=os.environ.get("ARA_CLI_LIMIT", 200),
|
|
help=("Only expire the first <limit> determined by the ordering. Defaults to ARA_CLI_LIMIT or 200.")
|
|
)
|
|
parser.add_argument(
|
|
"--confirm",
|
|
action="store_true",
|
|
help="Confirm expiration of objects, otherwise runs without expiring any objects",
|
|
)
|
|
# fmt: on
|
|
return parser
|
|
|
|
def take_action(self, args):
|
|
client = get_client(
|
|
client=args.client,
|
|
endpoint=args.server,
|
|
timeout=args.timeout,
|
|
username=args.username,
|
|
password=args.password,
|
|
verify=False if args.insecure else True,
|
|
run_sql_migrations=False,
|
|
)
|
|
|
|
if not args.confirm:
|
|
self.log.info("--confirm was not specified, no objects will be expired")
|
|
|
|
query = dict(status="running")
|
|
# generate a timestamp from n days ago in a format we can query the API with
|
|
# ex: 2019-11-21T00:57:41.702229
|
|
query["updated_before"] = (datetime.now() - timedelta(hours=args.hours)).isoformat()
|
|
query["order"] = args.order
|
|
query["limit"] = args.limit
|
|
|
|
endpoints = ["/api/v1/playbooks", "/api/v1/plays", "/api/v1/tasks"]
|
|
for endpoint in endpoints:
|
|
objects = client.get(endpoint, **query)
|
|
self.log.info("Found %s objects matching query on %s" % (objects["count"], endpoint))
|
|
# TODO: Improve client validation and exception handling
|
|
if "count" not in objects:
|
|
# If we didn't get an answer we can parse, it's probably due to an error 500, 403, 401, etc.
|
|
# The client would have logged the error.
|
|
self.log.error(
|
|
"Client failed to retrieve results, see logs for ara.clients.offline or ara.clients.http."
|
|
)
|
|
sys.exit(1)
|
|
|
|
for obj in objects["results"]:
|
|
link = "%s/%s" % (endpoint, obj["id"])
|
|
if not args.confirm:
|
|
self.log.info(
|
|
"Dry-run: %s would have been expired, status is running since %s" % (link, obj["updated"])
|
|
)
|
|
else:
|
|
self.log.info("Expiring %s, status is running since %s" % (link, obj["updated"]))
|
|
client.patch(link, status="expired")
|
|
self.expired += 1
|
|
|
|
self.log.info("%s objects expired" % self.expired)
|