Example #1
0
def get_roles_by_book(_id):
    record = Book.find_one(({'_id': ObjectId(_id)}))
    if not record:
        return jsonify({
            'message': 'book not found',
            'code': '104001',
        }), 400

    book_id = str(record['_id'])
    check_playbook(book_id)
    condition = {'book_id': book_id, 'role': 'roles', 'is_dir': True}

    parent = db.collection('playbook').find_one(condition)
    if not parent:
        return jsonify({
            'message': 'ok',
            'code': 0,
            'data': [],
        })

    where = {'book_id': book_id, 'is_dir': True, 'parent': parent.get('path')}
    cursor = db.collection('playbook').find(where)
    records = list(cursor)

    return jsonify({
        'message': 'ok',
        'code': 0,
        'data': records,
    })
Example #2
0
def get_playbook(_id):
    book = Book.find_one({'_id': ObjectId(_id)})
    if not book or not int(book.get('status')):
        return jsonify({
            'message': 'invalid id',
            'code': 154001,
        }), 400

    cursor = Playbook.find({'book_id': str(book.get('_id'))})
    cursor = cursor.sort([('is_edit', pymongo.ASCENDING),
                          ('path', pymongo.ASCENDING)])

    return jsonify({
        'message': 'ok',
        'code': 0,
        'data': list(cursor),
    })
Example #3
0
def edit_book(_id):
    params = request.get_json() or request.form
    if not params:
        return jsonify({
            'message': 'invalid params',
            'code': 154000,
        }), 400

    name = params.get('name')
    description = params.get('description')
    status = params.get('status', 1)
    maintainer = params.get('maintainer', [])
    import_type = params.get('importType')
    galaxy_repo = params.get('galaxyRepo')
    record = Book.find_one({'_id': ObjectId(_id)})
    if not record:
        return jsonify({
            'message': 'record not found',
            'code': 154041,
        }), 404

    data = {
        'status': status,
    }

    if name:
        data['name'] = name

    if description:
        data['description'] = description

    if maintainer:
        data['maintainer'] = maintainer

    if import_type == 'galaxy':
        galaxy = AnsibleGalaxy([galaxy_repo], {'force': True})
        galaxy.install(record.get('_id'))

    Book.update_one({'_id': ObjectId(_id)}, {'$set': data}, upsert=True)
    logger.info('book update', extra={'record': record, 'changed': data})

    return jsonify({
        'message': 'ok',
        'code': 0,
        'data': data,
    })
Example #4
0
def get_entry(_id):
    book = Book.find_one(({'_id': ObjectId(_id)}))

    if not book:
        return jsonify({'message': 'book not found', 'code': 164000}), 400

    where = {
        'book_id': str(book.get('_id')),
        'is_dir': False,
        'role': 'entry',
    }
    cursor = Playbook.find(where)

    return jsonify({
        'message': 'ok',
        'code': 0,
        'data': list(cursor),
    })
Example #5
0
    def build_book_from_history(self, build_id):
        history = db.collection('build_history').find_one(
            {'_id': ObjectId(build_id)})
        task_id = history.get('task_id')
        file_id = history.get('file_id')
        job_info = history.get('job_info')
        book = Book.find_one({'_id': ObjectId(job_info.get('book_id'))})
        bookspace = self.get_book_space(book.get('name'))
        bookspace = os.path.join(bookspace, md5(str(task_id)))
        self.mkdir(bookspace)
        save_file = NamedTemporaryFile(delete=False, suffix='.zip').name
        with open(save_file, 'wb') as fd:
            db.fs_bucket().download_to_stream(ObjectId(file_id), fd)

        extract(save_file, bookspace)
        os.unlink(save_file)

        return bookspace
Example #6
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', 1)
    bid = params.get('_id')
    import_type = params.get('importType')
    galaxy_repo = params.get('galaxyRepo')
    maintainer = params.get('maintainer', [])
    if bid:
        record = Book.find_one({'_id': ObjectId(bid)})
        if not record:
            return jsonify({
                'message': 'record not found',
                'code': 154041,
            }), 404

    else:
        if import_type == 'galaxy' and galaxy_repo:
            galaxy = AnsibleGalaxy([galaxy_repo])
            galaxy.install()
            logger.info('import galaxy', extra={'repo': galaxy_repo})

    data = {
        'name': name,
        'description': description,
        'maintainer': maintainer,
        'import_type': import_type,
        'galaxy_repo': galaxy_repo,
        'status': int(status),
        'created_at': int(time.time())
    }

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

    return jsonify({
        'message': 'ok',
        'code': 0,
        'data': data,
    })
Example #7
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 #8
0
    def load_book_from_db(self, name, roles=None, build_id=False):
        book = Book.find_one({'name': name})
        if not book:
            return False
        files = Model.build_model('playbook').find({'book_id': str(book['_id'])})\
            .sort([('is_edit', pymongo.ASCENDING), ('path', pymongo.ASCENDING)])
        files = list(files)
        if not files:
            return False
        if build_id:
            bookspace = os.path.join(self.book, md5(str(build_id)))
        else:
            bookspace = self.get_book_space(name)

        def parse_register(record):
            register = record.get('register')
            if not register:
                return record

            c_ids = map(lambda i: ObjectId(i), register)
            cfg_records = Configuration.find({'_id': {'$in': list(c_ids)}})
            if not cfg_records:
                return record

            try:
                variables = {}
                content = yaml.safe_load(record.get('content', ''))
                if not content:
                    return record

                vault = Vault({'vault_pass': config.vault.get('secret')})
                for cfg in cfg_records:
                    config_vars = cfg.get('variables')
                    if not config_vars:
                        continue

                    for k, v in config_vars.items():
                        key = '_'.join(
                            ['ECLOGUE', 'CONFIG',
                             cfg.get('name', ''), k])
                        is_encrypt = Vault.is_encrypted(v)
                        value = v
                        if is_encrypt:
                            value = vault.decrypt_string(value)

                        variables[key] = value

                content = dict(content)
                content.update(variables)
                record['content'] = yaml.safe_dump(content)
            except Exception as e:
                print(e)
            return record

        self.check_workspace(path=self._check_make(bookspace))
        for item in files:
            item = parse_register(item)
            if roles and item.get('folder'):
                folder = item.get('folder')
                if folder and folder not in roles:
                    continue
            filename = bookspace + item.get('path')
            if item['is_dir']:
                if os.path.isdir(filename):
                    continue

                self.mkdir(filename)
            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']:
                    Model.build_model('playbooks').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)
        return bookspace
Example #9
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 #10
0
def upload():
    files = request.files
    form = request.form
    if not form or not form.get('parent'):
        return jsonify({
            'message': 'illegal param',
            'code': 104000,
        }), 400
    if not files.get('files'):
        return jsonify({
            'message': 'illegal param',
            'code': 104001,
        }), 400
    parent_id = form.get('parent')
    book_id = form.get('bookId')
    if parent_id == '/' and book_id:
        book = Book.find_one({'_id': ObjectId(book_id)})
        if not book:
            return jsonify({
                "message": "record not found",
                "code": 104040,
            }), 404

        current = {'path': '/', 'book_id': book_id}
    else:
        current = Playbook.find_one({'_id': ObjectId(parent_id)})
    if not current:
        return jsonify({
            "message": "current path not found",
            "code": 104004,
        }), 400
    file = files['files']
    filename = file.filename
    path = os.path.join(current['path'], filename)
    # parent = Playbook.find_one({'book_id': book_id, 'path': os.path.dirname(path)})
    record = {
        'book_id': book_id,
        'path': path,
        'is_dir': False,
        'parent': os.path.dirname(path),
    }
    meta = get_meta(path)
    record.update(meta)
    can_edit = is_edit(file)
    if not can_edit:
        file_id = db.save_file(filename=filename, fileobj=file)
        record['file_id'] = file_id
    else:
        content = file.read()
        content = content.decode('utf-8')
        record['content'] = content

    record['is_edit'] = can_edit
    record['created_at'] = int(time.time())
    record['updated_at'] = datetime.datetime.now().isoformat()
    # where = {
    #     'path': path,
    #     'book_id': ObjectId(book_id)
    # }
    # update = {
    #     '$set': record,
    # }
    check_playbook_node(record)
    # Playbook.update_one(where, update=update, upsert=True)

    return jsonify({
        'message': 'ok',
        'code': 0,
    })
Example #11
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,
    })
Example #12
0
    def import_book_from_dir(self,
                             home_path,
                             book_id,
                             exclude=['*.retry'],
                             links=False):
        bucket = []
        cursor = 0
        parent = home_path
        book_record = Book.find_one({'_id': ObjectId(book_id)})
        pattern = '|'.join(exclude).replace('*', '.*?')
        for current, dirs, files in os.walk(home_path,
                                            topdown=True,
                                            followlinks=links):
            pathname = current.replace(home_path, '') or '/'
            if exclude:
                match = re.search(pattern, pathname)
                if match:
                    continue

            dir_record = {
                'book_id': str(book_record.get('_id')),
                'path': pathname,
                'is_dir': True,
                'is_edit': False,
                'seq_no': cursor,
                'parent': None,
                'created_at': int(time.time()),
            }
            if not current == home_path:
                dir_record['parent'] = parent
                meta = Workspace.get_meta(pathname=pathname)
                dir_record.update(meta)
                dir_record['additions'] = meta

            parent = pathname
            bucket.append(dir_record)
            for file in files:
                pathname = parent.rstrip('/') + '/' + file
                if exclude:
                    match = re.match(pattern, pathname)
                    if match:
                        continue

                cursor += 1
                filename = current + '/' + file
                can_edit = is_edit(filename)
                file_record = dir_record.copy()
                file_record['is_edit'] = can_edit
                file_record['path'] = pathname
                file_record['parent'] = parent
                file_record['is_dir'] = False
                file_record['seq_no'] = cursor
                if is_edit:
                    with open(filename, 'r', encoding='utf-8') as fd:
                        file_record['content'] = fd.read()
                        file_record['md5'] = md5(file_record['content'])
                        file_record['is_encrypt'] = Vault.is_encrypted(
                            file_record['content'])

                meta = self._get_role(file_record['path'])
                file_record.update(meta)
                file_record['additions'] = meta
                bucket.append(file_record)
            cursor += 1
        is_entry = filter(lambda i: i.get('role') == 'entry', bucket)
        is_entry = list(is_entry)
        if not is_entry:
            path = '/entry.yml'
            entry = {
                'book_id': str(book_record.get('_id')),
                'path': path,
                'is_dir': False,
                'is_edit': True,
                'seq_no': 0,
                'content': '',
                'parent': None,
                'created_at': int(time.time()),
            }
            meta = self._get_role(path)
            entry.update(meta)
            entry['additions'] = meta
            bucket.append(entry)

        return bucket