Example #1
0
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')
    wk = Workspace()
    res = wk.load_book_from_db(name=data.get('book_name'),
                               roles=data.get('roles'))
    if not res:
        return jsonify({
            'message': 'load book failed',
            'code': 104000,
        }), 400

    return jsonify({'message': 'ok', 'code': 0, 'data': 1})
Example #2
0
 def test_import_playbook_from_dir(self):
     book = self.get_data('book')
     self.add_data(Book, book)
     book_id = str(book['_id'])
     try:
         wk = Workspace()
         home_path = os.path.dirname(wk.get_book_space(book['name']))
         result = wk.import_book_from_dir(home_path,
                                          str(book_id),
                                          prefix='/')
         self.assertIs(len(result) > 0, True)
     finally:
         Playbook().collection.delete_many({'book_id': book_id})
Example #3
0
    def install(self, workspace='job'):
        project_id = self.config.get('project_id')
        job_id = self.config.get('job_id')
        if workspace == 'job':
            home_path = self.job_space(project_id)
        else:
            home_path = self.build_space(project_id)

        Workspace.mkdir(home_path)
        store = home_path + '/' + job_id + '.zip'
        result = self.dowload_artifact(project_id, job_id, store)
        if not result:
            raise Exception('gitlab download artifacts failed')

        return home_path
Example #4
0
    def default_options(self):
        wk = Workspace()
        roles_path = [wk.get_galaxy_space()]

        return {
            'verbosity': 3,
            'force': False,
            'role_file': None,
            'keep_scm_meta': False,
            'roles_path': roles_path,
            'api_server': 'https://galaxy.ansible.com',
            'ignore_certs': True,
            'ignore_errors': False,
            'no_deps': False,
            'offline': False,
        }
Example #5
0
def check_playbook(book_id):
    record = book.find_by_id(book_id)
    if not record:
        raise Exception('invalid playbook')

    records = Playbook.find({'book_id': book_id})
    for item in records:
        parent = item.get('parent')
        if not item.get('parent'):
            continue

        p_item = Playbook.find_one({'book_id': book_id, 'path': parent})
        if not p_item:
            p_path = os.path.dirname(parent)
            p_path = p_path if p_path != '/' else None
            data = {
                'path': parent,
                'parent': p_path,
                'is_dir': True,
                'is_edit': False,
                'book_id': book_id,
                'role': os.path.basename(parent),
                'created_at': time.time(),
            }

            meta = Workspace.get_meta(parent)
            data.update(meta)
            data['additions'] = meta
            Playbook.insert_one(data)

    return True
Example #6
0
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()
    wk.load_book_from_db(name)
    dirname = wk.get_book_space(name)
    filename = name + '.zip'
    with NamedTemporaryFile('w+t', delete=False) as fd:
        make_zip(dirname, fd.name)

        return send_file(fd.name,
                         attachment_filename=filename,
                         as_attachment=True)
Example #7
0
 def sync_mirror(self):
     dirname = self.cache_dir + '/' + self.project
     if not self.is_cached():
         Workspace.mkdir(dirname)
         git = Git(dirname)
         git.execute(['git', 'clone', '--mirror', self.repository, dirname])
         command = ['git', 'remote', 'add', 'eclogue', self.repository]
         git.execute(command)
         self.logger.info(' '.join(command))
         command = [
             'git', 'remote', 'set-url', '--push', 'origin', self.repository
         ]
         git.execute(command)
         self.logger.info(' '.join(command))
         command = ['git', 'remote', 'update', '--prune', 'origin']
         git.execute(command)
         self.logger.info(' '.join(command))
Example #8
0
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),
            }
        })
Example #9
0
def install_book_from_dir(dirname, book_id):
    wk = Workspace()
    bucket = wk.import_book_from_dir(dirname, book_id)
    playbooks = Playbook.find({'book_id': book_id})
    files = map(lambda i: i['path'], bucket)
    paths = map(lambda i: i['path'], playbooks)
    diff = list(set(paths) - set(files))
    for item in diff:
        Playbook.delete_one({'book_id': book_id, 'path': item})

    mapping = {}
    map(lambda i: {mapping['path']: i}, playbooks)
    for item in bucket:
        record = mapping.get(item['path'])
        if not record:
            Playbook.insert_one(item)
            continue
        if record['additions']:
            item['additions'].update(record['additions'])
            Playbook.update_one({'_id': record['_id']}, {'$set': item})
Example #10
0
    def install(self, workspace='job'):
        app_path = self.image.replace(':', '/')
        if workspace == 'job':
            home_path = self.job_space(app_path)
        else:
            home_path = self.build_space(app_path)

        working_dir = self.config.get('working_dir')
        Workspace.mkdir(home_path)
        filename = md5(str(uuid.uuid4()))
        store = home_path + '/' + filename + '.tar'
        with open(store, 'wb') as tar:
            bits, stat = self.get_archive(working_dir)
            for chunk in bits:
                tar.write(chunk)

            extract(store, home_path)
            os.unlink(store)
            # @todo store to mongodb gridfs
            if self.config.get('task_id'):
                pass
Example #11
0
 def __init__(self, options, build_type='job'):
     self.options = options
     repository, project, version = self.parse_repository()
     self.repository = repository
     self.project = project
     self.version = version
     self.cache_dir = Workspace().get_vcs_space('git')
     self.build_type = build_type
     self.workspace = self.cwd
     self.git = Git(working_dir=self.cwd)
     self.refs = None
     self.logger = get_logger('console')
Example #12
0
 def load_book_from_db(self, name, roles=None):
     wk = Workspace()
     workspace = wk.workspace
     wk.check_workspace()
     books = db.collection('playbook').find({
         'book_name': name
     }).sort('seq_no', pymongo.ASCENDING)
     for item in books:
         if roles:
             folder = item.get('name')
             if folder and folder not in roles:
                 continue
         filename = workspace + item['path']
         if item['is_dir']:
             if os.path.isdir(filename):
                 continue
             else:
                 os.mkdir(filename, 0o600)
         else:
             if os.path.isfile(filename):
                 file_hash = self.file_md5(filename)
                 if item.get('md5') and item['md5'] == file_hash:
                     continue
             dirname = os.path.dirname(filename)
             if not os.path.exists(dirname):
                 os.makedirs(dirname)
             if item['is_edit']:
                 db.collection('playbook').update_one(
                     {'_id': item['_id']},
                     {'$set': {
                         'md5': md5(item['content'].encode('utf8'))
                     }})
                 with open(filename, 'w') as stream:
                     stream.write(item['content'])
             else:
                 with open(filename, 'wb') as stream:
                     db.fs_bucket().download_to_stream(
                         item['file_id'], stream)
     return books
Example #13
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 #14
0
def build_book_from_db(name, roles=None, build_id=None, history_id=None):
    bookspace = ''
    wk = Workspace()
    try:
        if history_id:
            bookspace = wk.build_book_from_history(history_id)
        else:
            bookspace = wk.load_book_from_db(name, roles=roles, build_id=build_id)
        yield bookspace
    finally:
        if bookspace:
            wk.remove_directory(bookspace)
Example #15
0
    def setup():
        wk = Workspace()
        workspace = wk.workspace
        check_workspace()
        if not os.path.exists(workspace):
            os.makedirs(workspace, 0o755)
        books = db.collection('playbook').find().sort('path', pymongo.ASCENDING)
        # books = collection_array(books)
        start = time.time()
        for item in books:
            filename = workspace + item['path']
            if item['is_dir']:
                if os.path.isdir(filename):
                    continue
                else:
                    os.makedirs(filename, 0o755)
            else:
                if os.path.isfile(filename):
                    file_hash = file_md5(filename)
                    if item.get('md5') and item['md5'] == file_hash:
                        continue
                dirname = os.path.dirname(filename)
                if not os.path.exists(dirname):
                    os.makedirs(dirname)
                if item['is_edit']:
                    db.collection('playbook').update_one({'_id': item['_id']}, {'$set': {'md5': md5(item['content'])}})
                    with open(filename, 'w+') as stream:
                        stream.write(item['content'])
                else:
                    with open(filename, 'wb') as stream:
                        db.fs_bucket().download_to_stream(item['file_id'], stream)
        end = time.time()

        return jsonify({
            "message": "ok",
            "code": 0,
            'runtime': end - start
        })
Example #16
0
    def install(self, book_id=None):
        """
        copy from ansible-galaxy
        uses the args list of roles to be installed, unless -f was specified. The list of roles
        can be a name (which will be downloaded via the galaxy API and github), or it can be a local .tar.gz file.
        """
        role_file = self.options.role_file
        if len(self.repo) == 0 and role_file is None:
            # the user needs to specify one of either --role-file or specify a single user/role name
            raise AnsibleOptionsError("- you must specify a user/role name or a roles file")

        no_deps = self.options.no_deps
        force = self.options.force

        roles_left = []
        if role_file:
            try:
                f = open(role_file, 'r')
                if role_file.endswith('.yaml') or role_file.endswith('.yml'):
                    try:
                        required_roles = yaml.safe_load(f.read())
                    except Exception as e:
                        raise AnsibleError("Unable to load data from the requirements file: %s" % role_file)

                    if required_roles is None:
                        raise AnsibleError("No roles found in file: %s" % role_file)

                    for role in required_roles:
                        if "include" not in role:
                            role = RoleRequirement.role_yaml_parse(role)
                            if "name" not in role and "scm" not in role:
                                raise AnsibleError("Must specify name or src for role")
                            roles_left.append(GalaxyRole(self.galaxy, **role))
                        else:
                            with open(role["include"]) as f_include:
                                try:
                                    roles_left += [
                                        GalaxyRole(self.galaxy, **r) for r in
                                        (RoleRequirement.role_yaml_parse(i) for i in yaml.safe_load(f_include))
                                    ]
                                except Exception as e:
                                    msg = "Unable to load data from the include requirements file: %s %s"
                                    raise AnsibleError(msg % (role_file, e))
                else:
                    raise AnsibleError("Invalid role requirements file")
                f.close()
            except (IOError, OSError) as e:
                raise AnsibleError('Unable to open %s: %s' % (role_file, str(e)))
        else:
            # roles were specified directly, so we'll just go out grab them
            # (and their dependencies, unless the user doesn't want us to).
            for rname in self.repo:
                role = RoleRequirement.role_yaml_parse(rname.strip())
                roles_left.append(GalaxyRole(self.galaxy, **role))

        installed_role = []
        for role in roles_left:
            # only process roles in roles files when names matches if given
            if role_file and self.repo and role.name not in self.repo:
                print('Skipping role %s' % role.name)
                continue

            # query the galaxy API for the role data

            if role.install_info is not None:
                if role.install_info['version'] != role.version or force:
                    if force:
                        print('- changing role %s from %s to %s' %
                                    (role.name, role.install_info['version'], role.version or "unspecified"))
                        role.remove()
                    else:
                        print('- %s (%s) is already installed - use --force to change version to %s' %
                                    (role.name, role.install_info['version'], role.version or "unspecified"))
                        installed_role.append(role.name)
                        continue
                else:
                    if not force:
                        print('- %s is already installed, skipping.' % str(role))
                        continue

            try:
                installed = role.install()
                if installed and book_id:
                    wk = Workspace()
                    documents = wk.import_book_from_dir(os.path.dirname(role.path), book_id)
                    for doc in documents:
                        if doc.get('role') != 'entry':
                            doc['path'] = '/roles' + doc.get('path')
                        print(doc['path'])
                        Playbook().collection.update_one({'path': doc.get('path')}, {'$set': doc}, upsert=True)

            except AnsibleError as e:
                print("- %s was NOT installed successfully: %s " % (role.name, str(e)))
                # self.exit_without_ignore()
                continue

            # install dependencies, if we want them
            if not no_deps and installed:
                if not role.metadata:
                    print("Meta file %s is empty. Skipping dependencies." % role.path)
                else:
                    role_dependencies = role.metadata.get('dependencies') or []
                    for dep in role_dependencies:
                        logger.debug('Installing dep %s' % dep)
                        dep_req = RoleRequirement()
                        dep_info = dep_req.role_yaml_parse(dep)
                        dep_role = GalaxyRole(self.galaxy, **dep_info)
                        if '.' not in dep_role.name and '.' not in dep_role.src and dep_role.scm is None:
                            # we know we can skip this, as it's not going to
                            # be found on galaxy.ansible.com
                            continue
                        if dep_role.install_info is None:
                            if dep_role not in roles_left:
                                print('- adding dependency: %s' % str(dep_role))
                                roles_left.append(dep_role)
                            else:
                                print('- dependency %s already pending installation.' % dep_role.name)
                        else:
                            if dep_role.install_info['version'] != dep_role.version:
                                print(
                                    '- dependency %s from role %s differs from already installed version (%s), skipping' %
                                    (str(dep_role), role.name, dep_role.install_info['version']))
                            else:
                                print('- dependency %s is already installed, skipping.' % dep_role.name)

            if not installed:
                print("- %s was NOT installed successfully." % role.name)
                # self.exit_without_ignore()

        for role in installed_role:
            wk = Workspace()
            # wk.import_book_from_dir(self.options.roles_path)
        return 0
Example #17
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 #18
0
def playbook(payload):
    payload = payload or {}
    print(payload)
    book_id = payload.get('book_id')
    cmd = payload.get('cmd')
    if not book_id and not cmd:
        emit('playbook', {'code': 1404, 'message': 'invalid params'})
    book = Book.find_by_id(book_id)
    if not book:
        emit('playbook', {'code': 1404, 'message': 'book not found'})
    args = cmd.lstrip().split()
    allow_cmd = ['ls', 'll', 'cat', 'ansible-playbook', 'cd', 'pwd']
    if args[0] not in allow_cmd:
        return emit('playbook', {'code': 1403, 'message': 'invalid command'})

    # with build_book_from_db(book.get('name')) as cwd:
    cwd = payload.get('cwd') or ''
    cwd = cwd.strip('/')
    wk = Workspace()
    book_space = wk.load_book_from_db(book['name'])
    try:
        if args[0] == 'ansible-playbook':
            task_id = dispatch(
                book_id, 'entry.yml',
                {'options': 'ansible-playbook -i hosts entry.yml -t test'})
            if not task_id:
                return emit('playbook', {'message': ''})
            print('fuckkkkkkkkkkkkkk', task_id)
            return emit(
                'book_task', {
                    'code': 0,
                    'type': 'task',
                    'message': 'waiting for task launch...',
                    'data': {
                        'state': 'pending',
                        'taskId': str(task_id),
                    }
                })
        cwd = os.path.join(book_space, cwd)
        if args[0] == 'cd':
            if not args[1]:
                return emit({'code': 1400, 'message': 'invalid args'})
            cwd = os.path.join(cwd, './' + args[1])
            cwd = os.path.realpath(cwd)
            if len(cwd) < len(book_space):
                cwd = book_space
            args = ['ls', '-a']
        process = subprocess.Popen(
            args,
            cwd=cwd,
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
        )
        stdout, stderr = process.communicate()
        emit(
            'playbook', {
                'code': 0,
                'result': {
                    'stdout': stdout.decode().replace(book_space, ''),
                    'stderr': stdout.decode().replace(book_space, ''),
                    'cwd': cwd.replace(book_space, '')
                }
            })
    except Exception as err:
        print(err)
        emit('playbook', {
            'code': 1500,
            'message': str(err).replace(book_space, '')
        })
Example #19
0
def add_book():
    params = request.get_json() or request.form
    if not params:
        return jsonify({
            'message': 'invalid params',
            'code': 154000,
        }), 400

    name = params.get('name')
    if not name:
        return jsonify({
            'message': 'name param required',
            'code': 154001,
        }), 400

    existed = Book.find_one({'name': name})
    if existed:
        return jsonify({
            'message': 'book exist',
            'code': 154003,
        }), 400

    description = params.get('description')
    status = params.get('status', 0)
    book_id = params.get('_id')
    import_type = params.get('importType')
    repo = params.get('repo')
    maintainer = params.get('maintainer', [])
    readonly = params.get('readonly', False)

    if book_id:
        record = Book.find_by_id(book_id)
        if not record:
            return jsonify({
                'message': 'record not found',
                'code': 154041,
            }), 404
    else:
        data = {
            'name': name,
            'readonly': readonly,
            'description': description,
            'maintainer': maintainer,
            'import_type': import_type,
            'repo': repo,
            'created_at': int(time.time())
        }
        result = Book.insert_one(data)
        book_id = result.inserted_id
        if import_type == 'galaxy' and repo:
            galaxy = AnsibleGalaxy([repo])
            galaxy.install(book_id)
            logger.info('import galaxy', extra={'repo': repo})
        elif import_type == 'git' and repo:
            git = GitDownload({'repository': repo})
            dest = git.install()
            Workspace().import_book_from_dir(dest, book_id, exclude=['.git'])
    data = {
        'readonly': readonly,
        'description': description,
        'maintainer': maintainer,
        'import_type': import_type,
        'repo': repo,
        'status': int(status),
        'updated_at': time.time(),
    }

    Book.update_one({'_id': ObjectId(book_id)}, {'$set': data}, upsert=True)
    data['_id'] = book_id

    return jsonify({
        'message': 'ok',
        'code': 0,
        'data': data,
    })
Example #20
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)
Example #21
0
def edit_file(_id):
    """
    edit playbook file
    @todo add lock
    :param _id: ObjectId string
    :return: json
    """
    params = request.get_json() or request.form
    if not params:
        return jsonify({
            'message': 'invalid params',
            'code': 154000,
        }), 400

    edit_type = params.get('type')
    if edit_type == 'upload':
        return upload_file(_id)

    name = params.get('name')
    role = params.get('role')
    description = params.get('description')
    status = params.get('status', 1)
    maintainer = params.get('maintainer', [])
    can_edit = params.get('is_edit')
    is_dir = params.get('is_dir')
    is_encrypt = params.get('is_encrypt')
    folder = params.get('folder')
    register = params.get('register')
    content = params.get('content')
    record = Playbook.find_by_id(_id)
    if not record:
        return jsonify({
            'message': 'record not found',
            'code': 154041,
        }), 404

    data = {
        'status': status,
    }

    if name:
        data['name'] = name
    if role:
        data['role'] = role
    if folder:
        data['folder'] = folder
    if content:
        data['content'] = content
        data['md5'] = md5(content)
    if description:
        data['description'] = description
    if maintainer:
        data['maintainer'] = maintainer
    if can_edit is not None:
        data['is_edit'] = bool(is_edit)
        data['is_encrypt'] = bool(is_encrypt)
    if is_dir is not None:
        data['is_dir'] = bool(is_dir)
    if register:
        c_ids = map(lambda i: ObjectId(i), register)
        where = {'_id': {'$in': c_ids}}
        register_config = Configuration.find(where)
        if not register_config:
            return jsonify({
                'message': 'invalid register config',
                'code': 154042,
            }), 404

        data['register'] = register

    Playbook.update_one({'_id': ObjectId(_id)}, {'$set': data}, upsert=True)
    data['_id'] = _id
    book = Book.find_one({'_id': ObjectId(record['book_id'])})
    wk = Workspace()
    wk.write_book_file(book.get('name'), record)

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