def shrink(self, pool, pool_ticket, issue, cowboy_mode=False): pool = Session.merge(pool) pool_ticket = Session.merge(pool_ticket) self.task = Session.merge(self.task) try: c_start = JiraApi.get_now() jira.start_crq(issue, log=self.log, cowboy_mode=cowboy_mode) for t in issue.fields.subtasks: t_start = JiraApi.get_now() t2 = jira.instance.issue(t.key) jira.start_task(t2, log=self.log, cowboy_mode=cowboy_mode) for a in t2.fields.attachment: pool_id, vm_id = a.filename.split('.', 2)[:2] member = PoolMembership.query.filter_by(pool=pool, vm_id=vm_id).first() member.retire() Session.delete(member) Session.commit() self.log.msg("Retired VM {} and removed it as member of pool {}".format(member.vm_id, pool.name)) jira.complete_task(t, start_time=t_start, log=self.log, cowboy_mode=cowboy_mode) self.log.msg("waiting for 120 seconds before running post task diagnostics") time.sleep(120) run_diagnostics_on_pool(pool, self.log) jira.complete_crq(issue, start_time=c_start, log=self.log, cowboy_mode=cowboy_mode) except Exception as e: self.log.err("Error occured: {}".format(e)) jira.cancel_crq_and_tasks(issue, comment="an exception occured running this change: {}".format(e)) raise e finally: pool_ticket.done = True Session.merge(pool_ticket) Session.commit()
def update(self, pool, pool_ticket, issue, cowboy_mode=False): pool = Session.merge(pool) pool_ticket = Session.merge(pool_ticket) self.task = Session.merge(self.task) one_proxy = OneProxy(pool.cluster.zone.xmlrpc_uri, pool.cluster.zone.session_string, verify_certs=False) try: c_start = JiraApi.get_now() jira.start_crq(issue, log=self.log, cowboy_mode=cowboy_mode) for t in issue.fields.subtasks: t_start = JiraApi.get_now() t2 = jira.instance.issue(t.key) jira.start_task(t2, log=self.log, cowboy_mode=cowboy_mode) updated_members = [] for a in t2.fields.attachment: pool_id, vm_id = a.filename.split('.', 2)[:2] template = a.get().decode(encoding="utf-8", errors="strict") member = PoolMembership.query.filter_by(pool=pool, vm_id=vm_id).first() vm_name = member.vm_name member.retire() Session.delete(member) Session.commit() new_id = one_proxy.create_vm(template=template) new_member = PoolMembership(pool=pool, vm_name=vm_name, vm_id=new_id, template=template, date_added=datetime.utcnow()) Session.add(new_member) Session.commit() self.log.msg( "Instantiated new VM ID {} and added as member of pool {}". format(new_member.vm_id, pool.name)) updated_members.append(new_member) self.log.msg( "waiting for 120 seconds before running post change diagnostics" ) time.sleep(120) run_diagnostics_on_pool(pool, self.log) jira.complete_task(t, start_time=t_start, log=self.log, cowboy_mode=cowboy_mode) jira.complete_crq(issue, start_time=c_start, log=self.log, cowboy_mode=cowboy_mode) except Exception as e: self.log.err("Error occured: {}".format(e)) jira.cancel_crq_and_tasks( issue, comment="an exception occured running this change: {}".format(e)) raise e finally: pool_ticket.done = True Session.merge(pool_ticket) Session.commit()
def diagnostic_worker(q, results, log): while True: work = q.get() member = Session.merge(work['member']) diagnostic = Diagnostic(user=app.config['SSH_HEALTH_CHECK_USER'], host=member.vm_name, ssh_identity_file=app.config['SSH_IDENTITY_FILE'], cmd=app.config['SSH_HEALTH_CHECK_CMD'], timeout=app.config['SSH_HEALTH_CHECK_TIMEOUT']) try: run_diagnostic(diagnostic) log.msg("diagnostic against {} succeeded".format(diagnostic.host)) except Exception as e: log.err("diagnostic error: {}".format(e)) finally: Session.add(PoolMemberDiagnostic( vm_id=member.vm_id, pool=member.pool, start_date=diagnostic.start_date, end_date=diagnostic.end_date, stdout=diagnostic.stdout, stderr=diagnostic.stderr, exitcode=diagnostic.exitcode)) Session.commit() results.append(diagnostic) q.task_done()
def diagnostic_worker(q, results, log): while True: work = q.get() member = Session.merge(work['member']) diagnostic = Diagnostic( user=app.config['SSH_HEALTH_CHECK_USER'], host=member.vm_name, ssh_identity_file=app.config['SSH_IDENTITY_FILE'], cmd=app.config['SSH_HEALTH_CHECK_CMD'], timeout=app.config['SSH_HEALTH_CHECK_TIMEOUT']) try: run_diagnostic(diagnostic) log.msg("diagnostic against {} succeeded".format(diagnostic.host)) except Exception as e: log.err("diagnostic error: {}".format(e)) finally: Session.add( PoolMemberDiagnostic(vm_id=member.vm_id, pool=member.pool, start_date=diagnostic.start_date, end_date=diagnostic.end_date, stdout=diagnostic.stdout, stderr=diagnostic.stderr, exitcode=diagnostic.exitcode)) Session.commit() results.append(diagnostic) q.task_done()
def worker(q, number): while True: work = q.get() member = Session.merge(work['member']) vm = work['vm'] diagnostic = work['diagnostic'] try: logging.info("[{}] about to run diagnostic on {}".format(number, diagnostic.host)) diagnostic.run() logging.info("[{}] finished running diagnostic on {} (exit code: {})".format(number, vm.id, diagnostic.exitcode)) Session.add(PoolMemberDiagnostic( vm_id=vm.id, pool=member.pool, start_date=diagnostic.start_date, end_date=diagnostic.end_date, stdout=diagnostic.stdout, stderr=diagnostic.stderr, exitcode=diagnostic.exitcode)) Session.commit() logging.info("[{}] Saved diagnostic for {}".format(number, vm.id)) except Exception as e: defect_ticket = jira.defect_for_exception( summary_title="Lifeguard: Health Check => {})".format(e), tb=traceback.format_exc(), e=e) logging.error("[{} worker experienced an error running diagnostic " "host {}, error: {}, created defect ticket {}".format( number, vm.name, e, defect_ticket.key)) finally: q.task_done()
def expand(self, pool, pool_ticket, issue, cowboy_mode=False): new_vm_ids = [] pool = Session.merge(pool) pool_ticket = Session.merge(pool_ticket) self.task = Session.merge(self.task) one_proxy = OneProxy(pool.cluster.zone.xmlrpc_uri, pool.cluster.zone.session_string, verify_certs=False) try: c_start = JiraApi.get_now() jira.start_crq(issue, log=self.log, cowboy_mode=cowboy_mode) for t in issue.fields.subtasks: t_start = JiraApi.get_now() t2 = jira.instance.issue(t.key) jira.start_task(t2, log=self.log, cowboy_mode=cowboy_mode) for a in t2.fields.attachment: pool_id, vm_name = a.filename.split('.', 2)[:2] template = a.get().decode(encoding="utf-8", errors="strict") vm_id = one_proxy.create_vm(template=template) new_vm_ids.append(vm_id) m = PoolMembership(pool=pool, vm_name=vm_name, vm_id=vm_id, template=a.get(), date_added=datetime.utcnow()) Session.merge(m) Session.commit() self.log.msg("created new vm: {}".format(vm_name)) jira.complete_task(t, start_time=t_start, log=self.log, cowboy_mode=cowboy_mode) self.log.msg("waiting for 120 seconds before running post task diagnostics") time.sleep(120) run_diagnostics_on_pool(pool, self.log) jira.complete_crq(issue, start_time=c_start, log=self.log, cowboy_mode=cowboy_mode) except Exception as e: self.log.err("Error occured: {}".format(e)) jira.cancel_crq_and_tasks(issue, comment="an exception occured running this change: {}".format(e)) raise e finally: pool_ticket.done = True Session.merge(pool_ticket) Session.commit()
def run_task(self, **kwargs): Session.merge(self.task) self.task.start_time = datetime.utcnow() self.task.ident = threading.get_ident() self.task.status = TaskStatus.running.value Session.merge(self.task) Session.commit() try: self.run_function(**kwargs) self.task.log = self.log.messages self.task.end_time = datetime.utcnow() self.task.status = TaskStatus.finished.value self.task.result = TaskResult.success.value self.task = Session.merge(self.task) Session.commit() except Exception as e: self.task.log = self.log.messages self.task.tb = traceback.format_exc() self.task.end_time = datetime.utcnow() self.task.status = TaskStatus.finished.value self.task.result = TaskResult.fail.value self.task = Session.merge(self.task) Session.commit() defect = jira.defect_for_exception( "Background Task Error: {}".format(self.task.name), e, tb=traceback.format_exc(), username=self.task.username) self.task.defect_ticket = defect.key self.task = Session.merge(self.task) Session.commit() finally: Session.remove()
def run_task(self, **kwargs): Session.merge(self.task) self.task.start_time = datetime.utcnow() self.task.ident = threading.get_ident() self.task.status = TaskStatus.running.value Session.merge(self.task) Session.commit() try: self.run_function(**kwargs) self.task.log = self.log.messages self.task.end_time = datetime.utcnow() self.task.status = TaskStatus.finished.value self.task.result = TaskResult.success.value self.task = Session.merge(self.task) Session.commit() except Exception as e: self.task.log = self.log.messages self.task.tb = traceback.format_exc() self.task.end_time = datetime.utcnow() self.task.status = TaskStatus.finished.value self.task.result = TaskResult.fail.value self.task = Session.merge(self.task) Session.commit() defect = jira.defect_for_exception( "Background Task Error: {}".format( self.task.name), e, tb=traceback.format_exc(), username=self.task.username) self.task.defect_ticket = defect.key self.task = Session.merge(self.task) Session.commit() finally: Session.remove()
def shrink(self, pool, pool_ticket, issue, cowboy_mode=False): pool = Session.merge(pool) pool_ticket = Session.merge(pool_ticket) self.task = Session.merge(self.task) try: c_start = JiraApi.get_now() jira.start_crq(issue, log=self.log, cowboy_mode=cowboy_mode) for t in issue.fields.subtasks: t_start = JiraApi.get_now() t2 = jira.instance.issue(t.key) jira.start_task(t2, log=self.log, cowboy_mode=cowboy_mode) for a in t2.fields.attachment: pool_id, vm_id = a.filename.split('.', 2)[:2] member = PoolMembership.query.filter_by(pool=pool, vm_id=vm_id).first() member.retire() Session.delete(member) Session.commit() self.log.msg( "Retired VM {} and removed it as member of pool {}".format( member.vm_id, pool.name)) jira.complete_task(t, start_time=t_start, log=self.log, cowboy_mode=cowboy_mode) self.log.msg( "waiting for 120 seconds before running post task diagnostics") time.sleep(120) run_diagnostics_on_pool(pool, self.log) jira.complete_crq(issue, start_time=c_start, log=self.log, cowboy_mode=cowboy_mode) except Exception as e: self.log.err("Error occured: {}".format(e)) jira.cancel_crq_and_tasks( issue, comment="an exception occured running this change: {}".format(e)) raise e finally: pool_ticket.done = True Session.merge(pool_ticket) Session.commit()
def __init__(self, task, run_function, log=None, **kwargs): if None in [task, run_function]: raise Exception("Required parameter(s) is None: task={}, run_function={}".format(task, run_function)) if log is not None: self.log = log else: self.log = DumbLog() self.task = None self.task = Session.merge(task) self.run_function = types.MethodType(run_function, self) super().__init__(target=self.run_task, daemon=True, kwargs=kwargs)
def __init__(self, task, run_function, log=None, **kwargs): if None in [task, run_function]: raise Exception( "Required parameter(s) is None: task={}, run_function={}". format(task, run_function)) if log is not None: self.log = log else: self.log = DumbLog() self.task = None self.task = Session.merge(task) self.run_function = types.MethodType(run_function, self) super().__init__(target=self.run_task, daemon=True, kwargs=kwargs)
def create_update_ticket(name, pool, members, update_members): logging.info("[{}] {} requires updating and an existing change ticket doesn't exist".format(name, pool.name)) title = 'Plan Update => Pool {} ({}/{} members need updates)'.format(pool.name, len(members), pool.cardinality) description = "Pool update triggered that will update {} VM(s): \n\n*{}".format( len(update_members), "\n*".join([m.vm.name for m in update_members])) task = Task( name=title, description="{}\n{}".format(title, description), username="******") Session.add(task) Session.commit() task_thread = TaskThread(task=task, run_function=plan_update, pool=Session.merge(pool), update_members=update_members) threads.append(task_thread) logging.info("[{}] launched background task {} to {}".format(name, task.id, title))
def create_expansion_ticket(name, pool, members, expansion_names): logging.info("[{}] {} requires expansion and an existing change ticket doesn't exist".format(name, pool.name)) title = 'Plan Change => Pool Expansion: {} ({} members to {})'.format(pool.name, len(members), pool.cardinality) description = "Pool expansion triggered that will instantiate {} new VM(s): \n\n*{}".format( len(expansion_names), "\n*".join(expansion_names)) task = Task( name=title, description="{}\n{}".format(title, description), username="******") Session.add(task) Session.commit() task_thread = TaskThread(task=task, run_function=plan_expansion, pool=Session.merge(pool), expansion_names=expansion_names) threads.append(task_thread) logging.info("[{}] launched background task {} to {}".format(name, task.id, title))
def worker(name, q, cowboy_mode, plan, implement): while True: work = q.get() members = work['members'] pool = Session.merge(work['pool']) if cowboy_mode: name = "{}_{}".format('cowboy', name) logging.info("[{}] called in cowbow mode. All change management " "protocol around status/schedule will be ingored".format(name)) try: logging.info("[{}] assigned tickets for pool {}".format(name, pool.name)) if plan: existing_ticket = pool.pending_ticket() expansion_names = pool.get_expansion_names(members) shrink_members = pool.get_members_to_shrink(members) update_members = pool.get_update_members(members) if existing_ticket is not None: logging.info("[{}] existing expand ticket {} already created for {}".format( name, existing_ticket.ticket_key, pool.name)) elif expansion_names: create_expansion_ticket(name, pool, members, expansion_names) elif shrink_members: create_shrink_ticket(name, pool, members, shrink_members) elif update_members: create_update_ticket(name, pool, members, update_members) else: logging.info("[{}] skipping ticket planning".format(name)) if implement: execute_tickets(name, pool, cowboy_mode) else: logging.info("[{}] skipping ticket implementation".format(name)) logging.info("[{}] finished working on tickets for pool {}".format(name, pool.name)) except Exception as e: defect_ticket = jira.defect_for_exception( username="******", summary_title="Lifeguard: Health Check => {})".format(e), tb=traceback.format_exc(), e=e) logging.error("[{}] experienced an error pool {}, error: {}, created defect ticket {}".format( name, pool.name, e, defect_ticket.key)) finally: q.task_done()
def plan_update(self, pool, update_members): task = crq = None try: pool = Session.merge(pool) start, end = jira.next_immediate_window_dates() logging = jira.instance.issue('SVC-1020') crq = jira.instance.create_issue( project=app.config['JIRA_CRQ_PROJECT'], issuetype={'name': 'Change Request'}, assignee={'name': app.config['JIRA_USERNAME']}, summary="[IMPLEMENT] {}".format(self.task.name), description=self.task.description, customfield_14530=start, customfield_14531=end, customfield_19031={'value': 'Maintenance'}, customfield_15152=[{ 'value': 'Global' }], customfield_19430={'value': 'No conflict with any restrictions'}, customfield_14135={ 'value': 'IPG', 'child': { 'value': 'IPG Big Data' } }, customfield_17679="Pool update required") self.log.msg("Created change request: {}".format(crq.key)) jira.instance.transition_issue( crq, app.config['JIRA_TRANSITION_CRQ_PLANNING']) self.log.msg("Transitioned {} to planning".format(crq.key)) jira.instance.create_issue_link('Relate', crq, logging) self.log.msg("Related {} to LOGGING service {}".format( crq.key, logging.key)) batch_size = floor( len(update_members) / app.config['BATCH_SIZE_PERCENT']) batch_size = 1 if batch_size == 0 else batch_size num_batches = min(len(update_members), app.config['BATCH_SIZE_PERCENT']) self.log.msg( "updating {} hosts in pool {} requires {} tasks with no more than {} hosts per task" .format(len(update_members), pool.name, num_batches, batch_size)) batch_num = 0 while len(update_members): batch_num += 1 task = jira.instance.create_issue( issuetype={'name': 'MOP Task'}, assignee={'name': app.config['JIRA_USERNAME']}, project=app.config['JIRA_CRQ_PROJECT'], summary='[TASK {}/{} (Update {}%)] {}'.format( batch_num, num_batches, app.config['BATCH_SIZE_PERCENT'], self.task.name), parent={'key': crq.key}, customfield_14135={ 'value': 'IPG', 'child': { 'value': 'IPG Big Data' } }, customfield_15150={'value': 'No'}) self.log.msg("Created task: {}".format(task.key)) jira.instance.transition_issue( task, app.config['JIRA_TRANSITION_TASK_PLANNING']) self.log.msg("Transitioned {} to planning".format(task.key)) env = Environment(loader=ObjectLoader()) for num in range(0, min(len(update_members), batch_size)): m = update_members.pop() filename = '{}.{}.template'.format(m.pool.id, m.vm_id) attachment_content = io.StringIO(m.current_template()) jira.instance.add_attachment(issue=task, filename=filename, attachment=attachment_content) self.log.msg("Attached template for {} to task {}".format( filename, task.key)) jira.instance.transition_issue( task, app.config['JIRA_TRANSITION_TASK_WRITTEN']) self.log.msg("Transitioned task {} to written".format(task.key)) jira.approver_instance.transition_issue( task, app.config['JIRA_TRANSITION_TASK_APPROVED']) self.log.msg("Approved task {}".format(task.key)) jira.instance.transition_issue( crq, app.config['JIRA_TRANSITION_CRQ_PLANNED_CHANGE']) self.log.msg("Transitioned change request {} to approved".format( task.key)) jira.approver_instance.transition_issue( crq, app.config['JIRA_TRANSITION_CRQ_APPROVED']) self.log.msg("Transitioned change request {} to approved".format( crq.key)) self.log.msg("Task ID {}".format(self.task.id)) db_ticket = PoolTicket(pool=pool, action_id=PoolTicketActions.update.value, ticket_key=crq.key, task=Session.merge(self.task)) Session.add(db_ticket) Session.commit() except Exception as e: Session.rollback() if crq is not None: jira.cancel_crq_and_tasks( crq, comment="failure creating change tickets") raise e
def plan_shrink(self, pool, shrink_members): task = crq = None try: pool = Session.merge(pool) start, end = jira.next_immediate_window_dates() logging = jira.instance.issue('SVC-1020') crq = jira.instance.create_issue( project=app.config['JIRA_CRQ_PROJECT'], issuetype={'name': 'Change Request'}, assignee={'name': app.config['JIRA_USERNAME']}, summary="[IMPLEMENT] {}".format(self.task.name), description=self.task.description, customfield_14530=start, customfield_14531=end, customfield_19031={'value': 'Maintenance'}, customfield_15152=[{ 'value': 'Global' }], customfield_19430={'value': 'No conflict with any restrictions'}, customfield_14135={ 'value': 'IPG', 'child': { 'value': 'IPG Big Data' } }, customfield_17679="Pool shrink required") self.log.msg("Created change request: {}".format(crq.key)) jira.instance.transition_issue( crq, app.config['JIRA_TRANSITION_CRQ_PLANNING']) self.log.msg("Transitioned {} to planning".format(crq.key)) jira.instance.create_issue_link('Relate', crq, logging) self.log.msg("Related {} to LOGGING service {}".format( crq.key, logging.key)) task = jira.instance.create_issue( issuetype={'name': 'MOP Task'}, assignee={'name': app.config['JIRA_USERNAME']}, project=app.config['JIRA_CRQ_PROJECT'], summary='[IMPLEMENTATION TASK] {}'.format(self.task.name), parent={'key': crq.key}, customfield_14135={ 'value': 'IPG', 'child': { 'value': 'IPG Big Data' } }, customfield_15150={'value': 'No'}) self.log.msg("Created task: {}".format(task.key)) jira.instance.transition_issue( task, app.config['JIRA_TRANSITION_TASK_PLANNING']) self.log.msg("Transitioned {} to planning".format(task.key)) for m in [Session.merge(m) for m in shrink_members]: filename = '{}.{}.template'.format(pool.id, m.vm_id) attachment_content = io.StringIO(m.template) jira.instance.add_attachment(issue=task, filename=filename, attachment=attachment_content) self.log.msg("Attached member {} to shrink to task {}".format( filename, task.key)) jira.instance.transition_issue( task, app.config['JIRA_TRANSITION_TASK_WRITTEN']) self.log.msg("Transitioned task {} to written".format(task.key)) jira.approver_instance.transition_issue( task, app.config['JIRA_TRANSITION_TASK_APPROVED']) self.log.msg("Approved task {}".format(task.key)) jira.instance.transition_issue( crq, app.config['JIRA_TRANSITION_CRQ_PLANNED_CHANGE']) self.log.msg("Transitioned task {} to approved".format(task.key)) jira.approver_instance.transition_issue( crq, app.config['JIRA_TRANSITION_CRQ_APPROVED']) self.log.msg("Transitioned change request {} to approved".format( crq.key)) self.log.msg("Task ID {}".format(self.task.id)) db_ticket = PoolTicket(pool=pool, action_id=PoolTicketActions.shrink.value, ticket_key=crq.key, task=Session.merge(self.task)) Session.add(db_ticket) Session.commit() except Exception as e: if crq is not None: jira.cancel_crq_and_tasks( crq, comment="failure creating change tickets") raise e
def plan_expansion(self, pool, expansion_names): task = crq = None try: pool = Session.merge(pool) start, end = jira.next_immediate_window_dates() logging = jira.instance.issue('SVC-1020') crq = jira.instance.create_issue( project=app.config['JIRA_CRQ_PROJECT'], issuetype={'name': 'Change Request'}, assignee={'name': app.config['JIRA_USERNAME']}, summary='[TEST IMPLEMENT] {}'.format(self.task.name), description=self.task.description, customfield_14530=start, customfield_14531=end, customfield_19031={'value': 'Maintenance'}, customfield_15152=[{ 'value': 'Global' }], customfield_19430={'value': 'No conflict with any restrictions'}, customfield_14135={ 'value': 'IPG', 'child': { 'value': 'IPG Big Data' } }, customfield_17679="Pool expansion required") self.log.msg("Created change request: {}".format(crq.key)) jira.instance.transition_issue( crq, app.config['JIRA_TRANSITION_CRQ_PLANNING']) self.log.msg("Transitioned {} to planning".format(crq.key)) jira.instance.create_issue_link('Relate', crq, logging) self.log.msg("Related {} to LOGGING service {}".format( crq.key, logging.key)) task = jira.instance.create_issue( issuetype={'name': 'MOP Task'}, assignee={'name': app.config['JIRA_USERNAME']}, project=app.config['JIRA_CRQ_PROJECT'], description= "Instanitate the attached templates in the zone associated " "to the pool identified in the filename <pool_id>.<hostname>", summary='[TEST IMPLEMENTATION TASK] {}'.format(self.task.name), parent={'key': crq.key}, customfield_14135={ 'value': 'IPG', 'child': { 'value': 'IPG Big Data' } }, customfield_15150={'value': 'No'}) self.log.msg("Created task: {}".format(task.key)) jira.instance.transition_issue( task, app.config['JIRA_TRANSITION_TASK_PLANNING']) self.log.msg("Transitioned {} to planning".format(task.key)) env = Environment(loader=ObjectLoader()) for hostname in expansion_names: vars = VarParser.parse_kv_strings_to_dict( pool.cluster.zone.vars, pool.cluster.vars, pool.vars, 'hostname={}'.format(hostname)) vm_template = env.from_string(pool.template).render(pool=pool, vars=vars) attachment_content = io.StringIO(vm_template) jira.instance.add_attachment(issue=task, filename='{}.{}.template'.format( pool.id, hostname), attachment=attachment_content) self.log.msg("Attached template for {} to task {}".format( hostname, task.key)) jira.instance.transition_issue( task, app.config['JIRA_TRANSITION_TASK_WRITTEN']) self.log.msg("Transitioned task {} to written".format(task.key)) jira.approver_instance.transition_issue( task, app.config['JIRA_TRANSITION_TASK_APPROVED']) self.log.msg("Approved task {}".format(task.key)) jira.instance.transition_issue( crq, app.config['JIRA_TRANSITION_CRQ_PLANNED_CHANGE']) self.log.msg("Transitioned task {} to approved".format(task.key)) jira.approver_instance.transition_issue( crq, app.config['JIRA_TRANSITION_CRQ_APPROVED']) self.log.msg("Transitioned change request {} to approved".format( crq.key)) self.log.msg("Task ID {}".format(self.task.id)) db_ticket = PoolTicket(pool=Session.merge(pool), action_id=PoolTicketActions.expand.value, ticket_key=crq.key, task=Session.merge(self.task)) Session.add(db_ticket) Session.commit() except Exception as e: Session.rollback() if crq is not None: jira.cancel_crq_and_tasks( crq, comment="failure creating change tickets") raise e