diff --git a/fenix/utils/service.py b/fenix/utils/service.py index 5e46665..eb0b60e 100644 --- a/fenix/utils/service.py +++ b/fenix/utils/service.py @@ -135,7 +135,7 @@ class EngineEndpoint(object): return None LOG.info("EngineEndpoint: project_get_session") instance_ids = (self.workflow_sessions[session_id].session_data. - instance_ids_by_project(project_id)) + state_instance_ids(project_id)) return {'instance_ids': instance_ids} def project_update_session(self, ctx, session_id, project_id, data): diff --git a/fenix/workflow/workflow.py b/fenix/workflow/workflow.py index 1a8726b..c6c559e 100644 --- a/fenix/workflow/workflow.py +++ b/fenix/workflow/workflow.py @@ -46,11 +46,13 @@ class Project(object): def __init__(self, name): self.name = name self.state = None + self.state_instances = [] class SessionData(object): - def __init__(self, data): + def __init__(self, data, session_id): + self.session_id = session_id self.projects = [] self.hosts = data['hosts'] self.maintenance_at = str(data['maintenance_at']) @@ -68,7 +70,7 @@ class SessionData(object): def add_instance(self, project, instance_id, instance_name, host, ha=False): if host not in self.hosts: - LOG.error('%s: instance %s in invalid host ' % + LOG.error('%s: instance %s in invalid host %s' % (self.session_id, instance_id, host)) if project not in self.project_names(): self.projects.append(Project(project)) @@ -85,6 +87,40 @@ class SessionData(object): def set_projets_state(self, state): for project in self.projects: project.state = state + project.state_instances = [] + + def project_has_state_instances(self, name): + project = self.project(name) + if project.state_instances: + return True + else: + return False + + def set_projects_state_and_host_instances(self, state, host): + some_project_has_instances = False + for project in self.projects: + project.state = state + project.state_instances = ( + self.instance_ids_by_host_and_project(host, project.name)) + if project.state_instances: + some_project_has_instances = True + project.state = state + else: + project.state = None + if not some_project_has_instances: + LOG.error('%s: No project has instances on host %s' % + (self.session_id, host)) + + def get_projects_with_state(self): + return ([project for project in self.projects if project.state + is not None]) + + def state_instance_ids(self, name): + instances = ([project.state_instances for project in self.projects if + project.name == name][0]) + if not instances: + instances = self.instance_ids_by_project(name) + return instances def instances_by_project(self, project): return [instance for instance in self.instances if @@ -94,10 +130,15 @@ class SessionData(object): return [instance.instance_id for instance in self.instances if instance.project == project] + def instance_ids_by_host_and_project(self, host, project): + return [instance.instance_id for instance in self.instances + if instance.host == host and + instance.project == project] + def instances_by_host_and_project(self, host, project): return [instance for instance in self.instances - if instance.host == host - and instance.project == project] + if instance.host == host and + instance.project == project] def instance_action_by_project_reply(self, project, instance_id): return self.proj_instance_actions[project][instance_id] @@ -125,7 +166,7 @@ class BaseWorkflow(Thread): self.thg = threadgroup.ThreadGroup() self.timer = {} self.state = 'MAINTENANCE' - self.session_data = SessionData(data) + self.session_data = SessionData(data, session_id) self.states_methods = {'MAINTENANCE': 'maintenance', 'SCALE_IN': 'scale_in', 'PREPARE_MAINTENANCE': 'prepare_maintenance', diff --git a/fenix/workflow/workflows/default.py b/fenix/workflow/workflows/default.py index 50615d6..9d6a11e 100644 --- a/fenix/workflow/workflows/default.py +++ b/fenix/workflow/workflows/default.py @@ -181,15 +181,10 @@ class Workflow(BaseWorkflow): self.notif_admin.info({'some': 'context'}, 'maintenance.host', payload) - def projects_answer(self, state, projects=None): + def projects_answer(self, state, projects): state_ack = 'ACK_%s' % state state_nack = 'NACK_%s' % state - if projects: - state_projects = ([p for p in self.session_data.projects if - p.name in projects]) - else: - state_projects = self.session_data.projects - for project in state_projects: + for project in projects: pstate = project.state if pstate == state: break @@ -205,9 +200,13 @@ class Workflow(BaseWorkflow): break return pstate - def wait_projects_state(self, state, timer_name, projects=None): + def wait_projects_state(self, state, timer_name): state_ack = 'ACK_%s' % state state_nack = 'NACK_%s' % state + projects = self.session_data.get_projects_with_state() + if not projects: + LOG.error('%s: wait_projects_state %s. Emtpy project list' % + (self.session_id, state)) while not self.is_timer_expired(timer_name): answer = self.projects_answer(state, projects) if answer == state: @@ -263,7 +262,7 @@ class Workflow(BaseWorkflow): metadata = self.session_data.metadata self._project_notify(project, instance_ids, allowed_actions, actions_at, reply_at, state, metadata) - self.start_timer(self.conf.project_maintenance_reply, + self.start_timer(self.conf.project_scale_in_reply, 'SCALE_IN_TIMEOUT') return self.wait_projects_state(state, 'SCALE_IN_TIMEOUT') @@ -350,24 +349,16 @@ class Workflow(BaseWorkflow): # if instances on this host fits to other hosts return host_to_be_empty - def confirm_host_to_be_emptied(self, host, statebase): - state = statebase + def confirm_host_to_be_emptied(self, host, state): allowed_actions = ['MIGRATE', 'LIVE_MIGRATE', 'OWN_ACTION'] actions_at = self.reply_time_str(self.conf.project_maintenance_reply) reply_at = actions_at - self.session_data.set_projets_state(statebase) - projects = [] + self.session_data.set_projects_state_and_host_instances(state, host) for project in self.session_data.project_names(): - instances = ( - self.session_data.instances_by_host_and_project(host, project)) - if not instances: + if not self.session_data.project_has_state_instances(project): continue - projects.append(project) LOG.info('%s to project %s' % (state, project)) - info = "Instances\n" - for instance in instances: - info += ('%s\n' % instance) - LOG.info(info) + instance_ids = '%s/v1/maintenance/%s/%s' % (self.url, self.session_id, project) @@ -375,9 +366,8 @@ class Workflow(BaseWorkflow): self._project_notify(project, instance_ids, allowed_actions, actions_at, reply_at, state, metadata) self.start_timer(self.conf.project_maintenance_reply, - '%s_TIMEOUT' % statebase) - return self.wait_projects_state(state, '%s_TIMEOUT' % statebase, - projects) + '%s_TIMEOUT' % state) + return self.wait_projects_state(state, '%s_TIMEOUT' % state) def confirm_maintenance_complete(self): state = 'MAINTENANCE_COMPLETE' @@ -534,7 +524,7 @@ class Workflow(BaseWorkflow): (self.session_id)) self.state = 'PREPARE_MAINTENANCE' else: - LOG.info('Empty host found %') + LOG.info('Empty host found') self.state = 'START_MAINTENANCE' maint_at = self.str_to_datetime( @@ -572,9 +562,8 @@ class Workflow(BaseWorkflow): (self.session_id)) self.state = 'PREPARE_MAINTENANCE' else: - LOG.info('Empty host found %') + LOG.info('Empty host found') self.state = 'START_MAINTENANCE' - self.update_server_info() def prepare_maintenance(self): LOG.info("%s: prepare_maintenance called" % self.session_id)