Example #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})
Example #2
0
def get_job(_id):
    username = login_user.get('username')
    if not _id:
        return jsonify({'message': 'invalid id', 'code': 154000}), 400

    job = Job.find_one({
        '_id': ObjectId(_id),
        'maintainer': {
            '$in': [username]
        }
    })

    # @todo job status
    if not job:
        return jsonify({
            'message': 'invalid id',
            'code': 154001,
        }), 400

    template = job.get('template')
    inventory_type = template.get('inventory_type')
    inventory = template.get('inventory')
    if job.get('type') == 'adhoc':
        inventory_content = parse_cmdb_inventory(inventory)
        return jsonify({
            'message': 'ok',
            'code': 0,
            'data': {
                'record': job,
                'previewContent': inventory_content,
            },
        })

    if inventory_type == 'file':
        inventory_content = parse_file_inventory(inventory)
    else:
        inventory_content = parse_cmdb_inventory(inventory)

    check_playbook(job['book_id'])
    if inventory_type == 'file':
        book = Book.find_one({'_id': ObjectId(job['book_id'])})
        if not book:
            hosts = []
        else:
            hosts = get_inventory_by_book(book.get('_id'),
                                          book_name=book.get('name'))
    else:
        hosts = get_inventory_from_cmdb()

    roles = []
    condition = {
        'book_id': str(job['book_id']),
        'role': 'roles',
        'is_dir': True
    }
    parent = Playbook.find_one(condition)
    if parent:
        where = {
            'book_id': job['book_id'],
            'is_dir': True,
            'parent': parent.get('path')
        }
        cursor = Playbook.find(where)
        roles = list(cursor)

    logs = None
    task = Task.find_one({'job_id': _id})
    if task:
        log = db.collection('logs').find_one({'task_id': str(task['_id'])})
        if log:
            logs = log.get('message')

    return jsonify({
        'message': 'ok',
        'code': 0,
        'data': {
            'record': job,
            'previewContent': inventory_content,
            'hosts': hosts,
            'roles': roles,
            'logs': logs,
        },
    })
Example #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,
    })
Example #4
0
    def test_add_adhoc_job(self, parse_cmdb_inventory,
                           get_credential_content_by_id, adhoc_runner):
        data = self.get_data('adhoc_job')
        data['name'] = str(uuid.uuid4())
        url = self.get_api_path('/jobs')
        response = self.client.post(url, data='{}', headers=self.jwt_headers)
        self.assert400(response)
        self.assertResponseCode(response, 104000)
        params = data.copy()
        # None module params should response 400
        params['module'] = None
        params['type'] = 'adhoc'
        current_user = self.user
        params['maintainer'] = [current_user.get('username')]
        payload = self.body(params)
        response = self.client.post(url,
                                    data=payload,
                                    headers=self.jwt_headers)
        self.assert400(response)
        self.assertResponseCode(response, 104002)
        # test parse_cmdb_inventory return None
        parse_cmdb_inventory.return_value = None
        params['module'] = 'ls'
        payload = self.body(params)
        response = self.client.post(url,
                                    data=payload,
                                    headers=self.jwt_headers)
        self.assert400(response)
        self.assertResponseCode(response, 104004)

        # test with check and no private_key condition
        params['check'] = True
        params['private_key'] = None
        parse_cmdb_inventory.return_value = 'localhost'
        runner_instance = adhoc_runner.return_value
        runner_instance.get_result.return_value = data['name']
        payload = self.body(params)
        response = self.client.post(url,
                                    data=payload,
                                    headers=self.jwt_headers)
        self.assert200(response)
        runner_instance.run.assert_called()
        # test run with private_key
        params['private_key'] = True
        get_credential_content_by_id.return_value = None
        payload = self.body(params)
        response = self.client.post(url,
                                    data=payload,
                                    headers=self.jwt_headers)
        self.assert400(response)
        self.assertResponseCode(response, 104004)
        # assume get private_key return correct
        get_credential_content_by_id.return_value = 'test-private'
        response = self.client.post(url,
                                    data=payload,
                                    headers=self.jwt_headers)
        self.assert200(response)
        runner_instance.run.assert_called()
        params['check'] = False
        payload = self.body(params)
        response = self.client.post(url,
                                    data=payload,
                                    headers=self.jwt_headers)
        self.assert200(response)
        runner_instance.run.assert_called()
        response = self.client.post(url,
                                    data=payload,
                                    headers=self.jwt_headers)
        self.assert400(response)
        record = Job.find_one({'name': data['name']})
        assert record
        assert record.get('name') == data.get('name')
        params['job_id'] = str(ObjectId())
        payload = self.body(params)
        response = self.client.post(url,
                                    data=payload,
                                    headers=self.jwt_headers)
        self.assert404(response)
        self.assertResponseCode(response, 104040)
        params['job_id'] = str(record.get('_id'))
        payload = self.body(params)
        response = self.client.post(url,
                                    data=payload,
                                    headers=self.jwt_headers)
        self.assert200(response)
        Job().collection.delete_one({'name': data['name']})
Example #5
0
def job_webhook():
    query = request.args
    token = query.get('token')
    payload = request.get_json()
    if not payload or not token:
        return jsonify({'message': 'invalid params', 'code': 104000}), 400

    record = Job.find_one({'token': token})
    if not record:
        return jsonify({'message': 'illegal token', 'code': 104010}), 401

    if record.get('type') == 'adhoc':
        task_id = run_job(str(record.get('_id')))
        if not task_id:
            return jsonify({
                'message': 'try to queue task faield',
                'code': 104008
            }), 400

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

    template = record.get('template')
    app_id = template.get('app')
    income_params = {'cache': True}
    if app_id:
        app_info = Application.find_by_id(app_id)
        if not app_info:
            return jsonify({
                'message': 'app not found, please check your app',
                'code': 104001
            }), 400

        app_params = app_info.get('params')
        income = app_params.get('income')
        if income and payload.get('income'):
            income = Template(income)
            tpl = income.render(**payload.get('income'))
            tpl = yaml.safe_load(tpl)
            if tpl:
                income_params.update(tpl)

    task_id = run_job(str(record.get('_id')), **income_params)
    if not task_id:
        return jsonify({
            'message': 'put job enqueue failed',
            'code': 104002
        }), 400

    # if app_type == 'jenkins':
    #     build_id = '19'
    #     job_name = 'upward'
    #     run_job(_id, job_name, build_id)
    # elif app_type == 'gitlab':
    #     project_id = '13539397'
    #     job_id = '261939258'
    #     run_job(_id, project_id, job_id)
    # else:
    #     run_job(_id)

    # logger.error('test', extra={'a': {'b': 1}})

    return jsonify({'message': 'ok', 'code': 0, 'data': task_id})
Example #6
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', 0)
    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 = User.find({'username': {'$in': maintainer}})
        names = list(map(lambda i: i['username'], users))
        maintainer.extend(names)

    if login_user.get('username'):
        maintainer.append(login_user.get('username'))

    if not job_id:
        existed = Job.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_content:
        return jsonify({
            'message': 'invalid inventory',
            '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:
            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': 104004,
                    }), 400

                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 = Job.find_one({'_id': ObjectId(job_id)})
            if not record:
                return jsonify({
                    'message': 'record not found',
                    'code': 104040
                }), 404

            update = {
                '$set': data,
            }
            Job.update_one({'_id': ObjectId(job_id)}, update=update)
        else:
            Job.insert_one(data)

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