コード例 #1
0
ファイル: webhook.py プロジェクト: eclogue/eclogue
def gitlab_job(token):
    payload = request.get_json()
    object_type = payload.get('object_type')
    tag = payload.get('tag')
    job_id = payload.get('job_id')
    project_id = payload.get('project_id')
    job_status = payload.get('job_status')
    repository = payload.get('repository')
    record = Job().collection.find_one({'token': token})
    if not record:
        return jsonify({'message': 'invalid token', 'code': 104010}), 401

    if object_type != 'job':
        return jsonify({
            'message': 'only job event allow',
            'code': 104031
        }), 403

    if not job_id or not project_id or job_status != 'success':
        return jsonify({'message': 'invalid params', 'code': 104000}), 400

    if not tag:
        return jsonify({'message': 'only tag allow', 'code': 104032}), 403

    app_info = db.collection('apps').find_one(
        {'_id': ObjectId(record.get('app_id'))})
    if not app_info:
        return jsonify({
            'message': 'job must be bind with gitlab app',
            'code': 104002
        }), 400
    params = app_info.get('params') or {}
    if params.get('project_id') != project_id:
        return jsonify({'message': 'illegal project', 'code': 104003}), 400

    # if params.get('extract') == 'artifacts':
    #     wk = Workspace()
    #     filename = wk.get_gitlab_artifacts_file(record.get('name'), project_id, job_id)
    #     gitlab = GitlabApi().dowload_artifact(project_id, job_id, filename)
    #
    # if params.get('extract') == 'docker':
    #     pass
    integration = Integration(app_info.get('type'), params)
    integration.install()

    ansible_params = load_ansible_playbook(record)
    if ansible_params.get('message') is not 'ok':
        return jsonify(payload), 400

    data = ansible_params.get('data')
    with build_book_from_db(data.get('book_name'),
                            roles=data.get('roles')) as bookspace:
        if not bookspace:
            return jsonify({
                'message': 'load book failed',
                'code': 104000,
            }), 400

        return jsonify({'message': 'ok', 'code': 0, 'data': 1})
コード例 #2
0
ファイル: book.py プロジェクト: eclogue/eclogue
def download_book(_id):
    record = Book.find_by_id(_id)
    if not record:
        return jsonify({'message': 'record not found', 'code': 104040}), 404

    name = record.get('name')
    wk = Workspace()
    with build_book_from_db(name) as bookspace:
        filename = name + '.zip'
        with NamedTemporaryFile('w+t', delete=False) as fd:
            make_zip(bookspace, fd.name)

            return send_file(fd.name,
                             attachment_filename=filename,
                             as_attachment=True)
コード例 #3
0
ファイル: playbook.py プロジェクト: eclogue/eclogue
def get_tags():
    body = request.get_json()
    if not body:
        return jsonify({
            'message': 'miss required params',
            'code': 104000,
        }), 400

    template = body.get('template')
    listtags = template.get('listtags')
    listtasks = template.get('listtasks')
    if not listtags or not listtasks:
        return jsonify({
            'message': 'invalid params',
            'code': 104001,
        }), 400

    payload = load_ansible_playbook(body)
    if payload.get('message') is not 'ok':
        return jsonify(payload), 400

    data = payload.get('data')
    options = data.get('options')
    wk = Workspace()
    with build_book_from_db(name=data.get('book_name'),
                            roles=data.get('roles')) as bookspace:
        if not bookspace:
            return jsonify({
                'message': 'book not found',
                'code': 104000,
            }), 400

        entry = wk.get_book_entry(data.get('book_name'), data.get('entry'))
        play = PlayBookRunner([data['inventory']], options)
        play.run(entry)

        return jsonify({
            'message': 'ok',
            'code': 0,
            'data': {
                'tags': list(play.tags),
                'tasks': list(play.tasks),
            }
        })
コード例 #4
0
def check_job(_id):
    record = Job.find_one({'_id': ObjectId(_id)})
    if not record:
        return jsonify({'message': 'job not found', 'code': 104001}), 400

    body = {'template': record.get('template'), 'extra': record.get('extra')}

    payload = load_ansible_playbook(body)
    if payload.get('message') is not 'ok':
        return jsonify(payload), 400

    data = payload.get('data')
    options = data.get('options')
    private_key = data.get('private_key')
    wk = Workspace()
    res = build_book_from_db(name=data.get('book_name'),
                             roles=data.get('roles'))
    if not res:
        return jsonify({
            'message': 'book not found',
            'code': 104000,
        }), 400

    entry = wk.get_book_entry(data.get('book_name'), data.get('entry'))
    with NamedTemporaryFile('w+t', delete=True) as fd:
        key_text = get_credential_content_by_id(private_key, 'private_key')
        if not key_text:
            return jsonify({
                'message': 'invalid private_key',
                'code': 104033,
            }), 401
        fd.write(key_text)
        fd.seek(0)
        options['private_key'] = fd.name
        play = PlayBookRunner(data['inventory'], options)
        play.run(entry)
        result = play.get_result()

        return jsonify({'message': 'ok', 'code': 0, 'data': result})
コード例 #5
0
ファイル: book.py プロジェクト: eclogue/eclogue
def run(book_id, run_id, **options):
    perform = Perform.find_one({'run_id': run_id})
    book = Book.find_by_id(book_id)
    start_at = time.time()
    state = 'progressing'
    result = ''
    old_stdout = sys.stdout
    old_stderr = sys.stderr
    sys.stderr = sys.stdout = temp_stdout = Reporter(run_id)
    try:
        if book.get('repo') == 'git':
            vcs = GitDownload(book.get('repo_options'))
            install_path = vcs.install()
            # @todo

        book_name = book.get('name')
        with build_book_from_db(book_name, build_id=run_id) as dest:
            if not dest:
                result = 'install book failed'
                logger.warning(result)
                state = 'finish'
            else:
                inventory = options['inventory']
                if type(inventory == str):
                    inventory = os.path.join(dest, inventory)

                entry = os.path.join(dest, options['entry'].pop())
                if type(options['tags']) == str:
                    options['tags'] = options['tags'].split(',')
                options['basedir'] = dest
                print('xxxxxxxxxxxxx????', inventory, options)
                runner = PlayBookRunner(inventory, options)
                runner.run([entry])
                result = runner.get_result()
                print('result', result)
                state = 'finish'
    except Exception as err:
        result = str(err)
        extra = {'run_id': run_id}
        logger.error('run task with exception: {}'.format(result), extra=extra)
        state = 'error'
        raise err

    finally:
        content = temp_stdout.getvalue()
        temp_stdout.close(True)
        sys.stdout = old_stdout
        sys.stderr = old_stderr
        print(content)
        finish_at = time.time()
        update = {
            '$set': {
                'start_at': start_at,
                'finish_at': finish_at,
                'state': state,
                'duration': finish_at - start_at,
                'result': str(result),
                'trace': content,
            }
        }
        Perform.update_one({'_id': perform['_id']}, update=update)
コード例 #6
0
def lint(book_id, options, config=None):
    """
    base on ansiblelint
    refer to ansiblelint.__main__.py
    :param book_id:
    :param options:
    :param config:
    :return: None
    """
    formatter = formatters.Formatter()
    options = get_default_options(options)
    where = {
        'book_id': str(book_id),
        'role': 'entry',
    }
    entries = Playbook.find(where)
    if not entries:
        return False

    book = Book.find_by_id(book_id)
    if not book:
        return False

    if config:
        if 'quiet' in config:
            options.quiet = options.quiet or config['quiet']

        if 'parseable' in config:
            options.parseable = options.parseable or config['parseable']

        if 'parseable_severity' in config:
            options.parseable_severity = options.parseable_severity or \
                                         config['parseable_severity']

        if 'use_default_rules' in config:
            options.use_default_rules = options.use_default_rules or config['use_default_rules']

        if 'verbosity' in config:
            options.verbosity = options.verbosity + config['verbosity']

        options.exclude_paths.extend(
            config.get('exclude_paths', []))

        if 'rulesdir' in config:
            options.rulesdir = options.rulesdir + config['rulesdir']

        if 'skip_list' in config:
            options.skip_list = options.skip_list + config['skip_list']

        if 'tags' in config:
            options.tags = options.tags + config['tags']

    if options.quiet:
        formatter = formatters.QuietFormatter()

    if options.parseable:
        formatter = formatters.ParseableFormatter()

    if options.parseable_severity:
        formatter = formatters.ParseableSeverityFormatter()

    # no args triggers auto-detection mode
    # if len(args) == 0 and not (options.listrules or options.listtags):
    #     args = get_playbooks_and_roles(options=options)

    if options.use_default_rules:
        rulesdirs = options.rulesdir + [default_rulesdir]
    else:
        rulesdirs = options.rulesdir or [default_rulesdir]

    rules = RulesCollection()
    for rulesdir in rulesdirs:
        rules.extend(RulesCollection.create_from_directory(rulesdir))

    if options.listrules:
        return 0

    if options.listtags:
        return 0

    if isinstance(options.tags, six.string_types):
        options.tags = options.tags.split(',')

    skip = set()
    for s in options.skip_list:
        skip.update(str(s).split(','))

    options.skip_list = frozenset(skip)
    with build_book_from_db(book.get('name'), options.get('roles')) as book_path:
        playbooks = []
        for record in entries:
            entry = os.path.join(book_path, record['path'][1:])
            playbooks.append(entry)

        playbooks = sorted(set(playbooks))
        matches = list()
        checked_files = set()
        for playbook in playbooks:
            runner = Runner(rules, playbook, options.tags,
                            options.skip_list, options.exclude_paths,
                            options.verbosity, checked_files)
            matches.extend(runner.run())

        matches.sort(key=lambda x: (normpath(x.filename), x.linenumber, x.rule.id))
        results = []
        for match in matches:
            filename = str(match.filename)
            filename = filename.replace(book_path, '')
            results.append({
                'lineNumber': match.linenumber,
                'line': str(match.line),
                'rule': match.rule.id,
                'filename': filename,
                'message': match.message,
            })

        return results
コード例 #7
0
def add_jobs():
    """
    add job
    TODO(sang)
    :return: json
    """
    body = request.get_json()
    user = login_user
    if not body:
        return jsonify({
            'message': 'miss required params',
            'code': 104000,
        }), 400

    job_type = body.get('type')
    if job_type == 'adhoc':
        return add_adhoc()

    current_id = body.get('currentId')
    record = None
    if current_id:
        record = Job.find_by_id(current_id)
        if not record:
            return jsonify({'message': 'job not found', 'code': 104044}), 400

    payload = load_ansible_playbook(body)
    if payload.get('message') is not 'ok':
        return jsonify(payload), 400

    data = payload.get('data')
    options = data.get('options')
    is_check = body.get('check')
    private_key = data.get('private_key')
    wk = Workspace()
    book_name = data.get('book_name')
    roles = data.get('roles')
    with build_book_from_db(name=book_name, roles=roles) as bookspace:
        if not bookspace:
            return jsonify({'message': 'invalid book', 'code': 104000}), 400

        entry = wk.get_book_entry(data.get('book_name'), data.get('entry'))
        # entry = os.path.join(bookspace, data['entry'])
        dry_run = bool(is_check)
        options['check'] = dry_run
        if dry_run:
            with NamedTemporaryFile('w+t', delete=True) as fd:
                if private_key:
                    key_text = get_credential_content_by_id(
                        private_key, 'private_key')
                    if not key_text:
                        return jsonify({
                            'message': 'invalid private_key',
                            'code': 104033,
                        }), 401

                    fd.write(key_text)
                    fd.seek(0)
                    options['private_key'] = fd.name

                play = PlayBookRunner(data['inventory'],
                                      options,
                                      callback=CallbackModule())
                play.run(entry)

                return jsonify({
                    'message': 'ok',
                    'code': 0,
                    'data': {
                        'result': play.get_result(),
                        'options': options
                    }
                })

    name = data.get('name')
    existed = Job.find_one({'name': name})
    if existed and not current_id:
        return jsonify({
            'message': 'name existed',
            'code': 104001,
        }), 400

    token = str(base64.b64encode(bytes(current_request_id(), 'utf8')), 'utf8')
    new_record = {
        'name': name,
        'type': 'playbook',
        'token': token,
        'description': data.get('description'),
        'book_id': data.get('book_id'),
        'template': data.get('template'),
        'extra': data.get('extra'),
        'entry': data['entry'],
        'status': data['status'],
        'maintainer': [user.get('username')],
        'created_at': int(time.time()),
        'updated_at': datetime.datetime.now().isoformat(),
    }

    if record:
        Job.update_one({'_id': record['_id']}, update={'$set': new_record})
    else:
        Job.insert_one(new_record)

    return jsonify({
        'message': 'ok',
        'code': 0,
    })
コード例 #8
0
ファイル: dispatch.py プロジェクト: eclogue/eclogue
def run_playbook_task(_id, request_id, username, history_id, **kwargs):
    db = Mongo()
    record = Job.find_by_id(ObjectId(_id))
    task_record = TaskModel.find_one({'request_id': request_id})
    if not task_record:
        return False

    start_at = time()
    state = 'progressing'
    result = ''
    task_id = task_record.get('_id')
    job_id = task_record.get('job_id')
    old_stdout = sys.stdout
    old_stderr = sys.stderr
    sys.stderr = sys.stdout = temp_stdout = Reporter(str(task_id))
    try:
        if history_id:
            history = db.collection('build_history').find_one(
                {'_id': ObjectId(history_id)})
            record = history['job_info']
            kwargs = task_record.get('kwargs')

        template = record.get('template')
        body = {
            'template': record.get('template'),
            'extra': record.get('extra')
        }

        payload = load_ansible_playbook(body)
        if payload.get('message') is not 'ok':
            raise Exception('load ansible options error: ' +
                            payload.get('message'))

        app_id = template.get('app')
        if app_id:
            app_info = Application.find_by_id(ObjectId(app_id))
            if not app_info:
                raise Exception('app not found: {}'.format(app_id))

            app_type = app_info.get('type')
            app_params = app_info.get('params')
            if kwargs:
                app_params.update(kwargs)

            integration = Integration(app_type, app_params)
            integration.install()

        data = payload.get('data')
        options = data.get('options')
        private_key = data.get('private_key')
        roles = data.get('roles')
        bookname = data.get('book_name')
        with build_book_from_db(bookname,
                                roles=roles,
                                build_id=task_id,
                                history_id=history_id) as bookspace:
            if not bookspace or not os.path.isdir(bookspace):
                raise Exception(
                    'install playbook failed, book name: {}'.format(
                        data.get('book_name')))

            entry = os.path.join(bookspace, data.get('entry'))
            with NamedTemporaryFile('w+t', delete=False) as fd:
                if private_key:
                    key_text = get_credential_content_by_id(
                        private_key, 'private_key')
                    if not key_text:
                        raise Exception('invalid private_key')

                    fd.write(key_text)
                    fd.seek(0)
                    options['private-key'] = fd.name

                inventory = data.get('inventory')
                # hosts = os.path.join(bookspace, 'hosts.yml')
                # fileObject = open(hosts, mode='w+')
                # # fileObject.write(inventory)
                # yaml.dump_all(inventory, fileObject)
                # fileObject.close()
                play = PlayBookRunner(inventory, options, job_id=job_id)
                play.run(entry)
                result = play.get_result()
                builds = db.collection('build_history').count({'job_id': _id})
                state = 'finish'
                # @todo
                if builds > cache_result_number:
                    last_one = db.collection('build_history').find_one(
                        {'job_id': _id}, sort=[('_id', 1)])
                    if last_one:
                        db.fs().delete(last_one.get('file_id'))
                        db.collection('build_history').delete_one(
                            {'_id': last_one['_id']})

                with TemporaryDirectory() as dir_name:
                    bookname = data.get('book_name')
                    zip_file = os.path.join(dir_name, bookname)
                    zip_file = make_zip(bookspace, zip_file)
                    with open(zip_file, mode='rb') as stream:
                        filename = bookname + '.zip'
                        file_id = db.save_file(filename=filename,
                                               fileobj=stream)
                        store_info = {
                            'task_id': str(task_id),
                            'file_id': str(file_id),
                            'job_id': str(_id),
                            'job_info': record.to_dict(),
                            'filename': filename,
                            'created_at': time(),
                            'kwargs': kwargs,
                        }
                        db.collection('build_history').insert_one(store_info)
    except Exception as e:
        result = str(e)
        extra = {'task_id': task_id}
        logger.error('run task with exception: {}'.format(str(e)), extra=extra)
        state = 'error'
        extra_options = record.get('extra')
        user = User.find_one({'username': username})
        if user:
            user_id = str(user['_id'])
            notification = extra_options.get('notification')
            message = '[error]run job: {}, message: {}'.format(
                record.get('name'), str(e))
            sys.stdout.write(message)
            if notification and type(notification) == list:
                Notify().dispatch(user_id=user_id,
                                  msg_type='task',
                                  content=message,
                                  channel=notification)
        raise e
    finally:
        content = temp_stdout.getvalue()
        temp_stdout.close(True)
        sys.stdout = old_stdout
        sys.stderr = old_stderr
        finish_at = time()
        update = {
            '$set': {
                'start_at': start_at,
                'finish_at': finish_at,
                'state': state,
                'duration': finish_at - start_at,
                'result': str(result),
            }
        }
        TaskModel.update_one({'_id': task_id}, update=update)
        trace = {
            'task_id': str(task_id),
            'request_id': request_id,
            'username': username,
            'content': str(content),
            'created_at': time(),
        }
        db.collection('task_logs').insert_one(trace)