Esempio n. 1
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 = wk.load_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})
Esempio n. 2
0
def add_adhoc():
    payload = request.get_json()
    if not payload:
        return jsonify({
            'message': 'invalid params',
            'code': 104001,
        }), 400

    module = payload.get('module')
    args = payload.get('args')
    inventory = payload.get('inventory')
    private_key = payload.get('private_key')
    verbosity = payload.get('verbosity')
    name = payload.get('name')
    schedule = payload.get('schedule')
    check = payload.get('check')
    job_id = payload.get('job_id')
    extra_options = payload.get('extraOptions')
    status = int(payload.get('status', 0))
    notification = payload.get('notification')
    maintainer = payload.get('maintainer') or []
    if maintainer and isinstance(maintainer, list):
        users = db.collection('users').find({'username': {'$in': maintainer}})
        names = list(map(lambda i: i['username'], users))
        maintainer.extend(names)

    maintainer.append(login_user.get('username'))
    if not job_id:
        existed = db.collection('jobs').find_one({'name': name})
        if existed and existed.get('status') != -1:
            return jsonify({'message': 'name exist', 'code': 104007}), 400

    if not module or not inventory or not name:
        return jsonify({
            'message': 'miss required params',
            'code': 104002,
        }), 400

    # check_module = db.collection('ansible_modules').find_one({
    #     'name': module
    # })
    #
    # if not check_module:
    #     return jsonify({
    #         'message': 'invalid module',
    #         'code': 104003,
    #     }), 400

    inventory_content = parse_cmdb_inventory(inventory)
    if not inventory:
        return jsonify({
            'message': 'invalid inventory',
            'code': 104004,
        }), 400

    key_text = get_credential_content_by_id(private_key, 'private_key')
    if not key_text:
        return jsonify({
            'message': 'invalid private key',
            'code': 104004,
        }), 400

    options = {}
    if extra_options:
        options.update(extra_options)

    if verbosity:
        options['verbosity'] = verbosity

    if check:
        with NamedTemporaryFile('w+t', delete=True) as fd:
            fd.write(key_text)
            fd.seek(0)
            options['private_key'] = fd.name
            tasks = [{'action': {'module': module, 'args': args}}]
            hosts = inventory_content
            runner = AdHocRunner(hosts, options=options)
            runner.run('all', tasks)
            result = runner.get_result()

            return jsonify({'message': 'ok', 'code': 0, 'data': result})

    else:
        token = str(base64.b64encode(bytes(current_request_id(), 'utf8')),
                    'utf8')
        data = {
            'name': name,
            'template': {
                'inventory': inventory,
                'private_key': private_key,
                'verbosity': verbosity,
                'module': module,
                'args': args,
                'extraOptions': extra_options,
            },
            'extra': {
                'schedule': schedule,
                'notification': notification,
            },
            'token': token,
            'maintainer': maintainer,
            'type': 'adhoc',
            'created_at': time.time(),
            'status': status,
            'add_by': login_user.get('username')
        }

        if job_id:
            record = db.collection('jobs').find_one({'_id': ObjectId(job_id)})
            if not record:
                return jsonify({
                    'message': 'record not found',
                    'code': 104040
                }), 404

            update = {
                '$set': data,
            }
            db.collection('jobs').update_one({'_id': ObjectId(job_id)},
                                             update=update)
            logger.info('update job',
                        extra={
                            'record': record,
                            'changed': data
                        })
        else:
            result = db.collection('jobs').insert_one(data)
            data['_id'] = result.inserted_id
            logger.info('add job', extra={'record': data})

    return jsonify({
        'message': 'ok',
        'code': 0,
    })
Esempio n. 3
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()
    res = wk.load_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'))
    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,
    })
Esempio n. 4
0
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')
        wk = Workspace()
        roles = data.get('roles')
        if history_id:
            bookspace = wk.build_book(history_id)
        else:
            bookname = data.get('book_name')
            bookspace = wk.load_book_from_db(name=bookname,
                                             roles=roles,
                                             build_id=task_id)

        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

            options['tags'] = ['uptime']
            options['verbosity'] = 2
            inventory = data.get('inventory')
            logger.info('ansible-playbook run load inventory: \n{}'.format(
                yaml.safe_dump(inventory)))
            play = PlayBookRunner(data.get('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_numer:
                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,
                        'filename': filename,
                        'created_at': time(),
                        'kwargs': kwargs,
                    }
                    db.collection('build_history').insert_one(store_info)
                    shutil.rmtree(bookspace)

    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)

    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': 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)
Esempio n. 5
0
def run_adhoc_task(_id, request_id, username, history_id, **kwargs):
    db = Mongo()
    task_record = db.collection('tasks').find_one({'request_id': request_id})
    record = db.collection('jobs').find_one({'_id': ObjectId(_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:
        ret = load_ansible_adhoc(record)
        if ret.get('message') != 'ok':
            raise Exception(ret.get('message'))

        payload = ret.get('data')
        options = payload.get('options')
        private_key = payload.get('private_key')
        module = payload.get('module')
        args = payload.get('args')
        hosts = options['hosts']
        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:
                    raise Exception('invalid private_key')

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

            tasks = [{'action': {'module': module, 'args': args}}]
            runner = AdHocRunner(hosts, options=options, job_id=job_id)
            runner.run('all', tasks)
            result = runner.get_result()
            state = 'finish'
            update = {
                '$set': {
                    'result': result,
                    'state': state,
                }
            }
            db.collection('tasks').update_one({'_id': task_id}, update=update)
    except Exception as e:
        state = 'error'
        result = e.args
        extra = {'task_id': task_id}
        logger.error('run task with exception: {}'.format(str(e)), extra=extra)
        user = db.collection('users').find_one({'username': username})
        user_id = str(user['_id'])
        notification = record.get('notification')
        message = 'run job: {}, error:{}'.format(record.get('name'), str(e))
        sys.stdout.write(message)
        Notify().dispatch(user_id=user_id,
                          msg_type='task',
                          content=message,
                          channel=notification)

        raise e
    finally:
        content = temp_stdout.getvalue()
        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': result,
            }
        }

        db.collection('tasks').update_one({'_id': task_id}, update=update)
        trace = {
            'task_id': str(task_id),
            'request_id': request_id,
            'username': username,
            'content': content,
            'created_at': time(),
        }
        db.collection('task_logs').insert_one(trace)
Esempio n. 6
0
def load_ansible_adhoc(payload):
    template = payload.get('template')
    extra = payload.get('extra')
    module = template.get('module')
    args = template.get('args')
    inventory = template.get('inventory')
    private_key = template.get('private_key')
    verbosity = template.get('verbosity')
    become_method = template.get('become_method')
    become_user = template.get('become_user')
    extra_options = template.get('extraOptions')
    name = template.get('name')
    schedule = extra.get('schedule')

    if not module or not inventory:
        return {
            'message': 'miss required params',
            'code': 104002,
        }

    # check_module = db.collection('ansible_modules').find_one({
    #     'name': module
    # })
    #
    # if not check_module:
    #     return {
    #         'message': 'invalid module',
    #         'code': 104003,
    #     }

    inventory = parse_cmdb_inventory(inventory)
    if not inventory:
        return {
            'message': 'invalid inventory',
            'code': 104004,
        }

    key_text = get_credential_content_by_id(private_key, 'private_key')
    if not key_text:
        return {
            'message': 'invalid private key',
            'code': 104004,
        }

    options = {
        'verbosity': verbosity,
        'check': False,
        'hosts': inventory,
    }
    if become_method:
        options['become'] = 'yes'
        options['become_method'] = become_method
        if become_user:
            options['become_user'] = become_user

    if extra_options:
        options.update(extra_options)

    return {
        'message': 'ok',
        'data': {
            'inventory': inventory,
            'options': options,
            'name': name,
            'module': module,
            'args': args,
            'private_key': private_key,
            'template': payload,
            'schedule': schedule,
            'extra': extra,
        }
    }
Esempio n. 7
0
def run_task():
    payload = request.get_json()
    if not payload:
        return jsonify({
            'message': 'invalid params',
            'code': 114000,
        }), 400

    run_type = payload.get('type')
    inventory = payload.get('inventory')
    private_key = payload.get('private_key')
    module = payload.get('module')
    args = payload.get('args')
    entry = payload.get('entry')
    become_mehtod = payload.get('become_method')
    become_user = payload.get('become_user')
    verbosity = payload.get('verbosity', 0) or 1
    extra_options = payload.get('extraOptions')
    hosts = parse_cmdb_inventory(inventory)
    if not hosts:
        return jsonify({
            'message': 'invalid inventory',
            'code': 114001,
        }), 400

    options = {}
    if extra_options:
        options.update(extra_options)

    if verbosity:
        options['verbosity'] = verbosity

    if become_mehtod:
        options['become'] = 'yes'
        options['become_method'] = become_mehtod
        if become_user:
            options['become_user'] = become_user

    if run_type == 'adhoc':
        if not module:
            return jsonify({
                'message': 'invalid module',
                'code': 114002,
            }), 400

        tasks = [{'action': {'module': module, 'args': args}}]

        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

            runner = AdHocRunner(hosts, options=options)
            logger.info('run ansible-adhoc',
                        extra={
                            'hosts': hosts,
                            'options': options
                        })
            res = runner.run('all', tasks)
            result = runner.format_result()

            return jsonify({'message': 'ok', 'code': 0, 'data': result})
    else:
        if not entry:
            return jsonify({
                'message': 'invalid entry',
                'code': 114004,
            }), 400

        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

            with NamedTemporaryFile('w+t', delete=True) as fh:
                fh.write(entry)
                fh.seek(0)
                runner = PlayBookRunner(hosts, options)
                logger.info('run ansible-playbook',
                            extra={
                                'hosts': hosts,
                                'options': options
                            })
                runner.run(fh.name)
                result = runner.format_result()

                return jsonify({'message': 'ok', 'code': 0, 'data': result})
Esempio n. 8
0
def run(run_id, payload):
    perform = Perform.find_one({'run_id': run_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:
        run_type = payload.get('run_type')
        inventory = payload.get('inventory')
        inventory = parse_cmdb_inventory(inventory)
        private_key = payload.get('private_key')
        entry = payload.get('entry')
        options = payload.get('options')
        tasks = payload.get('tasks')
        if run_type == 'adhoc':
            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:
                        raise Exception('invalid private_key')
                    fd.write(key_text)
                    fd.seek(0)
                    options['private_key'] = fd.name
                runner = AdHocRunner(inventory, options=options)
                runner.run('all', tasks)
                result = runner.format_result()
                state = 'finish'
        else:
            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:
                        raise Exception('invalid private_key')
                    fd.write(key_text)
                    fd.seek(0)
                    options['private_key'] = fd.name

                with NamedTemporaryFile('w+t', delete=True) as fh:
                    fh.write(entry)
                    fh.seek(0)
                    runner = PlayBookRunner(inventory, options)
                    runner.run(fh.name)
                    result = runner.format_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
        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)