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})
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, })
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, })
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)
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)
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, } }
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})
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)