From 19fe1fcb17e3545fbc540760a2b2df3e522fd771 Mon Sep 17 00:00:00 2001 From: Dmitry Nikishov Date: Wed, 2 Nov 2016 16:05:55 +0300 Subject: [PATCH] Added audit run and outofsync commands fuel2 audit noop starts the noop run on the environment fuel2 audit list outofsync checks the puppet reports of the deployment task and extracts all the resources, that would have changed during the actual puppet run. Change-Id: Ibf2f5467fd6b05cf437f59fdb462bbde14635632 --- fuel_external_git/const.py | 2 + fuel_external_git/fuelclient_audit.py | 130 ++++++++++++++++++++++++++ setup.cfg | 2 + 3 files changed, 134 insertions(+) create mode 100644 fuel_external_git/fuelclient_audit.py diff --git a/fuel_external_git/const.py b/fuel_external_git/const.py index de421af..43d7682 100644 --- a/fuel_external_git/const.py +++ b/fuel_external_git/const.py @@ -12,3 +12,5 @@ REPOS_DIR = '/var/lib/fuel_repos' REPO_TTL = 1200 +TASK_RETRIES = 10 +TASK_RETRY_DELAY = 2 diff --git a/fuel_external_git/fuelclient_audit.py b/fuel_external_git/fuelclient_audit.py new file mode 100644 index 0000000..8b5067e --- /dev/null +++ b/fuel_external_git/fuelclient_audit.py @@ -0,0 +1,130 @@ +# 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. + +from __future__ import absolute_import + +import time + +from cliff import command +from cliff import lister + +from fuelclient import client +if hasattr(client, 'DefaultAPIClient'): + # Handling python-fuelclient version >= 10.0 + fc_client = client.DefaultAPIClient +else: + # Handling python-fuelclient version <= 9.0 + fc_client = client.APIClient +from fuelclient.common import data_utils +from fuelclient.objects import Environment +from fuelclient.objects import Task + +from fuel_external_git.const import TASK_RETRIES +from fuel_external_git.const import TASK_RETRY_DELAY + + +class AuditRun(lister.Lister, command.Command): + columns = ( + 'task_id', + ) + + def get_parser(self, prog_name): + parser = super(AuditRun, self).get_parser(prog_name) + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('--env', + type=int, + help='Associated Repo ID') + group.add_argument('--repo', + type=int, + help='Associated Repo ID') + return parser + + def take_action(self, parsed_args): + env_id = parsed_args.env + if not env_id: + repo_id = parsed_args.repo + repos = fc_client.get_request('/clusters/git-repos/') + env_id = [repo['env_id'] for repo in repos + if repo['id'] == repo_id][0] + + env = Environment(env_id) + # Due to how Nailgun handles such tasks, returned + # one will not contain any deployment-related data. + # So we'll have to fetch the last noop task with progress < 100 + env.redeploy_changes(noop_run=True) + for retry in xrange(TASK_RETRIES): + tasks = Task.get_all() + try: + task = filter(lambda t: t.data['status'] == 'running' and + t.data['name'] == 'dry_run_deployment', + tasks).pop() + break + except IndexError: + time.sleep(TASK_RETRY_DELAY) + continue + data = {'task_id': task.id} + data = data_utils.get_display_data_multi(self.columns, [data]) + return (self.columns, data) + + +class OutOfSyncResources(lister.Lister, command.Command): + columns = ( + 'task_id', + 'node_id', + 'resource' + ) + + def get_parser(self, prog_name): + parser = super(OutOfSyncResources, self).get_parser(prog_name) + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('--env', + type=int, + help='Environment to lookup changes on') + group.add_argument('--task', + type=int, + help='Task ID to lookup changes on') + return parser + + def take_action(self, parsed_args): + task_id = parsed_args.task + if not task_id: + all_tasks = Task.get_all() + env_tasks = filter( + lambda t: t.data['cluster'] == parsed_args.env and + t.data['name'] == 'dry_run_deployment', + all_tasks) + env_tasks.sort(key=lambda t: t.data['time_start']) + fuel_task = env_tasks[-1] + else: + fuel_task = Task(task_id) + + history = fuel_task.connection.get_request( + ('transactions/{tid}/' + 'deployment_history?include_summary=1').format(tid=fuel_task.id) + ) + changes = [] + changed_tasks = filter(lambda t: t['status'] != 'skipped' and + t.get('summary', {}) and + t['summary']['resources']['out_of_sync'] > 0, + history) + for task in changed_tasks: + name = task['task_name'] + for item in task['summary']['raw_report']: + if 'Would have triggered' not in item['message'] and \ + 'Finished catalog run' not in item['message']: + short_item = item['source'].replace('/Stage[main]/', '') + changes.append({'task_id': name, + 'resource': short_item, + 'node_id': task['node_id']}) + + data = data_utils.get_display_data_multi(self.columns, changes) + return (self.columns, data) diff --git a/setup.cfg b/setup.cfg index d578fb5..f3cd056 100644 --- a/setup.cfg +++ b/setup.cfg @@ -30,3 +30,5 @@ fuelclient: gitrepo_update = fuel_external_git.fuelclient_gitrepo:UpdateRepo gitrepo_init = fuel_external_git.fuelclient_gitrepo:InitRepo gitrepo_get_configs = fuel_external_git.fuelclient_gitrepo:DownloadConfgs + audit_noop = fuel_external_git.fuelclient_audit:AuditRun + audit_list_outofsync = fuel_external_git.fuelclient_audit:OutOfSyncResources