def test_listener_update(self, mock_driver, mock_generate_uuid, mock_log, mock_get_session, mock_listener_repo_get, mock_listener_repo_update, mock_amphora_repo_update): listener_update_obj = amphora_driver_tasks.ListenersUpdate() listener_update_obj.execute(_load_balancer_mock, [_listener_mock]) mock_driver.update.assert_called_once_with(_listener_mock, _vip_mock) # Test the revert amp = listener_update_obj.revert(_load_balancer_mock) repo.ListenerRepository.update.assert_called_once_with( _session_mock, id=LISTENER_ID, provisioning_status=constants.ERROR) self.assertIsNone(amp) # Test the revert with exception repo.ListenerRepository.update.reset_mock() mock_listener_repo_update.side_effect = Exception('fail') amp = listener_update_obj.revert(_load_balancer_mock) repo.ListenerRepository.update.assert_called_once_with( _session_mock, id=LISTENER_ID, provisioning_status=constants.ERROR) self.assertIsNone(amp)
def get_delete_member_flow(self): """Create a flow to delete a member :returns: The flow for deleting a member """ delete_member_flow = linear_flow.Flow(constants.DELETE_MEMBER_FLOW) delete_member_flow.add( lifecycle_tasks.MemberToErrorOnRevertTask(requires=[ constants.MEMBER, constants.LISTENERS, constants.LOADBALANCER, constants.POOL ])) delete_member_flow.add( database_tasks.MarkMemberPendingDeleteInDB( requires=constants.MEMBER)) delete_member_flow.add( model_tasks.DeleteModelObject( rebind={constants.OBJECT: constants.MEMBER})) delete_member_flow.add( database_tasks.DeleteMemberInDB(requires=constants.MEMBER)) delete_member_flow.add( amphora_driver_tasks.ListenersUpdate( requires=[constants.LOADBALANCER, constants.LISTENERS])) delete_member_flow.add( database_tasks.DecrementMemberQuota(requires=constants.MEMBER)) delete_member_flow.add( database_tasks.MarkPoolActiveInDB(requires=constants.POOL)) delete_member_flow.add( database_tasks.MarkLBAndListenersActiveInDB( requires=[constants.LOADBALANCER, constants.LISTENERS])) return delete_member_flow
def get_create_health_monitor_flow(self): """Create a flow to create a health monitor :returns: The flow for creating a health monitor """ create_hm_flow = linear_flow.Flow(constants.CREATE_HEALTH_MONITOR_FLOW) create_hm_flow.add( lifecycle_tasks.HealthMonitorToErrorOnRevertTask(requires=[ constants.HEALTH_MON, constants.LISTENERS, constants.LOADBALANCER ])) create_hm_flow.add( database_tasks.MarkHealthMonitorPendingCreateInDB( requires=constants.HEALTH_MON)) create_hm_flow.add( amphora_driver_tasks.ListenersUpdate( requires=[constants.LOADBALANCER, constants.LISTENERS])) create_hm_flow.add( database_tasks.MarkHealthMonitorActiveInDB( requires=constants.HEALTH_MON)) create_hm_flow.add( database_tasks.MarkPoolActiveInDB(requires=constants.POOL)) create_hm_flow.add( database_tasks.MarkLBAndListenersActiveInDB( requires=[constants.LOADBALANCER, constants.LISTENERS])) return create_hm_flow
def get_update_pool_flow(self): """Create a flow to update a pool :returns: The flow for updating a pool """ update_pool_flow = linear_flow.Flow(constants.UPDATE_POOL_FLOW) update_pool_flow.add( lifecycle_tasks.PoolToErrorOnRevertTask(requires=[ constants.POOL, constants.LISTENERS, constants.LOADBALANCER ])) update_pool_flow.add( database_tasks.MarkPoolPendingUpdateInDB(requires=constants.POOL)) update_pool_flow.add( model_tasks.UpdateAttributes( rebind={constants.OBJECT: constants.POOL}, requires=[constants.UPDATE_DICT])) update_pool_flow.add( amphora_driver_tasks.ListenersUpdate( requires=[constants.LOADBALANCER, constants.LISTENERS])) update_pool_flow.add( database_tasks.UpdatePoolInDB( requires=[constants.POOL, constants.UPDATE_DICT])) update_pool_flow.add( database_tasks.MarkPoolActiveInDB(requires=constants.POOL)) update_pool_flow.add( database_tasks.MarkLBAndListenersActiveInDB( requires=[constants.LOADBALANCER, constants.LISTENERS])) return update_pool_flow
def get_update_l7rule_flow(self): """Create a flow to update an L7 rule :returns: The flow for updating an L7 rule """ update_l7rule_flow = linear_flow.Flow(constants.UPDATE_L7RULE_FLOW) update_l7rule_flow.add( lifecycle_tasks.L7RuleToErrorOnRevertTask(requires=[ constants.L7RULE, constants.LISTENERS, constants.LOADBALANCER ])) update_l7rule_flow.add( database_tasks.MarkL7RulePendingUpdateInDB( requires=constants.L7RULE)) update_l7rule_flow.add( amphora_driver_tasks.ListenersUpdate( requires=[constants.LOADBALANCER, constants.LISTENERS])) update_l7rule_flow.add( database_tasks.UpdateL7RuleInDB( requires=[constants.L7RULE, constants.UPDATE_DICT])) update_l7rule_flow.add( database_tasks.MarkL7RuleActiveInDB(requires=constants.L7RULE)) update_l7rule_flow.add( database_tasks.MarkL7PolicyActiveInDB(requires=constants.L7POLICY)) update_l7rule_flow.add( database_tasks.MarkLBAndListenersActiveInDB( requires=[constants.LOADBALANCER, constants.LISTENERS])) return update_l7rule_flow
def get_update_member_flow(self): """Create a flow to update a member :returns: The flow for updating a member """ update_member_flow = linear_flow.Flow(constants.UPDATE_MEMBER_FLOW) update_member_flow.add(lifecycle_tasks.MemberToErrorOnRevertTask( requires=[constants.MEMBER, constants.LISTENERS, constants.LOADBALANCER])) update_member_flow.add(database_tasks.MarkMemberPendingUpdateInDB( requires=constants.MEMBER)) update_member_flow.add(model_tasks. UpdateAttributes( rebind={constants.OBJECT: constants.MEMBER}, requires=[constants.UPDATE_DICT])) update_member_flow.add(amphora_driver_tasks.ListenersUpdate( requires=[constants.LOADBALANCER, constants.LISTENERS])) update_member_flow.add(database_tasks.UpdateMemberInDB( requires=[constants.MEMBER, constants.UPDATE_DICT])) update_member_flow.add(database_tasks.MarkMemberActiveInDB( requires=constants.MEMBER)) update_member_flow.add(database_tasks. MarkLBAndListenersActiveInDB( requires=[constants.LOADBALANCER, constants.LISTENERS])) return update_member_flow
def test_listeners_update(self, mock_driver, mock_generate_uuid, mock_log, mock_get_session, mock_listener_repo_get, mock_listener_repo_update, mock_amphora_repo_update): listeners_update_obj = amphora_driver_tasks.ListenersUpdate() listeners = [ data_models.Listener(id='listener1'), data_models.Listener(id='listener2') ] vip = data_models.Vip(ip_address='10.0.0.1') lb = data_models.LoadBalancer(id='lb1', listeners=listeners, vip=vip) listeners_update_obj.execute(lb, listeners) mock_driver.update.assert_has_calls( [mock.call(listeners[0], vip), mock.call(listeners[1], vip)]) self.assertEqual(2, mock_driver.update.call_count) self.assertIsNotNone(listeners[0].load_balancer) self.assertIsNotNone(listeners[1].load_balancer) # Test the revert amp = listeners_update_obj.revert(lb) expected_db_calls = [ mock.call(_session_mock, id=listeners[0].id, provisioning_status=constants.ERROR), mock.call(_session_mock, id=listeners[1].id, provisioning_status=constants.ERROR) ] repo.ListenerRepository.update.has_calls(expected_db_calls) self.assertEqual(2, repo.ListenerRepository.update.call_count) self.assertIsNone(amp)
def get_update_l7policy_flow(self): """Create a flow to update an L7 policy :returns: The flow for updating an L7 policy """ update_l7policy_flow = linear_flow.Flow(constants.UPDATE_L7POLICY_FLOW) update_l7policy_flow.add(lifecycle_tasks.L7PolicyToErrorOnRevertTask( requires=[constants.L7POLICY, constants.LISTENERS, constants.LOADBALANCER])) update_l7policy_flow.add(database_tasks.MarkL7PolicyPendingUpdateInDB( requires=constants.L7POLICY)) update_l7policy_flow.add( model_tasks.UpdateAttributes( rebind={constants.OBJECT: constants.L7POLICY}, requires=[constants.UPDATE_DICT])) update_l7policy_flow.add(amphora_driver_tasks.ListenersUpdate( requires=[constants.LOADBALANCER, constants.LISTENERS])) update_l7policy_flow.add(database_tasks.UpdateL7PolicyInDB( requires=[constants.L7POLICY, constants.UPDATE_DICT])) update_l7policy_flow.add(database_tasks.MarkL7PolicyActiveInDB( requires=constants.L7POLICY)) update_l7policy_flow.add(database_tasks.MarkLBAndListenersActiveInDB( requires=[constants.LOADBALANCER, constants.LISTENERS])) return update_l7policy_flow
def get_delete_pool_flow(self): """Create a flow to delete a pool :returns: The flow for deleting a pool """ delete_pool_flow = linear_flow.Flow(constants.DELETE_POOL_FLOW) delete_pool_flow.add( lifecycle_tasks.PoolToErrorOnRevertTask(requires=[ constants.POOL, constants.LISTENERS, constants.LOADBALANCER ])) delete_pool_flow.add( database_tasks.MarkPoolPendingDeleteInDB(requires=constants.POOL)) delete_pool_flow.add( database_tasks.CountPoolChildrenForQuota( requires=constants.POOL, provides=constants.POOL_CHILD_COUNT)) delete_pool_flow.add( model_tasks.DeleteModelObject( rebind={constants.OBJECT: constants.POOL})) delete_pool_flow.add( amphora_driver_tasks.ListenersUpdate( requires=[constants.LOADBALANCER, constants.LISTENERS])) delete_pool_flow.add( database_tasks.DeletePoolInDB(requires=constants.POOL)) delete_pool_flow.add( database_tasks.DecrementPoolQuota( requires=[constants.POOL, constants.POOL_CHILD_COUNT])) delete_pool_flow.add( database_tasks.MarkLBAndListenersActiveInDB( requires=[constants.LOADBALANCER, constants.LISTENERS])) return delete_pool_flow
def get_create_member_flow(self): """Create a flow to create a member :returns: The flow for creating a member """ create_member_flow = linear_flow.Flow(constants.CREATE_MEMBER_FLOW) create_member_flow.add( lifecycle_tasks.MemberToErrorOnRevertTask(requires=[ constants.MEMBER, constants.LISTENERS, constants.LOADBALANCER, constants.POOL ])) create_member_flow.add( database_tasks.MarkMemberPendingCreateInDB( requires=constants.MEMBER)) create_member_flow.add( network_tasks.CalculateDelta(requires=constants.LOADBALANCER, provides=constants.DELTAS)) create_member_flow.add( network_tasks.HandleNetworkDeltas(requires=constants.DELTAS, provides=constants.ADDED_PORTS)) create_member_flow.add( amphora_driver_tasks.AmphoraePostNetworkPlug( requires=(constants.LOADBALANCER, constants.ADDED_PORTS))) create_member_flow.add( amphora_driver_tasks.ListenersUpdate( requires=(constants.LOADBALANCER, constants.LISTENERS))) create_member_flow.add( database_tasks.MarkMemberActiveInDB(requires=constants.MEMBER)) create_member_flow.add( database_tasks.MarkPoolActiveInDB(requires=constants.POOL)) create_member_flow.add( database_tasks.MarkLBAndListenersActiveInDB( requires=(constants.LOADBALANCER, constants.LISTENERS))) return create_member_flow
def get_update_load_balancer_flow(self): """Creates a flow to update a load balancer. :returns: The flow for update a load balancer """ update_LB_flow = linear_flow.Flow(constants.UPDATE_LOADBALANCER_FLOW) update_LB_flow.add( lifecycle_tasks.LoadBalancerToErrorOnRevertTask( requires=constants.LOADBALANCER)) update_LB_flow.add( model_tasks.UpdateAttributes( rebind={constants.OBJECT: constants.LOADBALANCER}, requires=[constants.UPDATE_DICT])) update_LB_flow.add( network_tasks.ApplyQos(requires=(constants.LOADBALANCER, constants.UPDATE_DICT))) update_LB_flow.add( amphora_driver_tasks.ListenersUpdate( requires=[constants.LOADBALANCER, constants.LISTENERS])) update_LB_flow.add( database_tasks.UpdateLoadbalancerInDB( requires=[constants.LOADBALANCER, constants.UPDATE_DICT])) update_LB_flow.add( database_tasks.MarkLBActiveInDB(requires=constants.LOADBALANCER)) return update_LB_flow
def get_update_health_monitor_flow(self): """Create a flow to update a health monitor :returns: The flow for updating a health monitor """ update_hm_flow = linear_flow.Flow(constants.UPDATE_HEALTH_MONITOR_FLOW) update_hm_flow.add(lifecycle_tasks.HealthMonitorToErrorOnRevertTask( requires=[constants.HEALTH_MON, constants.LISTENERS, constants.LOADBALANCER])) update_hm_flow.add(database_tasks.MarkHealthMonitorPendingUpdateInDB( requires=constants.HEALTH_MON)) update_hm_flow.add(model_tasks. UpdateAttributes( rebind={constants.OBJECT: constants.HEALTH_MON}, requires=[constants.UPDATE_DICT])) update_hm_flow.add(amphora_driver_tasks.ListenersUpdate( requires=[constants.LOADBALANCER, constants.LISTENERS])) update_hm_flow.add(database_tasks.UpdateHealthMonInDB( requires=[constants.HEALTH_MON, constants.UPDATE_DICT])) update_hm_flow.add(database_tasks.MarkHealthMonitorActiveInDB( requires=constants.HEALTH_MON)) update_hm_flow.add(database_tasks.MarkLBAndListenersActiveInDB( requires=[constants.LOADBALANCER, constants.LISTENERS])) return update_hm_flow
def get_delete_health_monitor_flow(self): """Create a flow to delete a health monitor :returns: The flow for deleting a health monitor """ delete_hm_flow = linear_flow.Flow(constants.DELETE_HEALTH_MONITOR_FLOW) delete_hm_flow.add(lifecycle_tasks.HealthMonitorToErrorOnRevertTask( requires=[constants.HEALTH_MON, constants.LISTENERS, constants.LOADBALANCER])) delete_hm_flow.add(database_tasks.MarkHealthMonitorPendingDeleteInDB( requires=constants.HEALTH_MON)) delete_hm_flow.add(model_tasks. DeleteModelObject(rebind={constants.OBJECT: constants.HEALTH_MON})) delete_hm_flow.add(amphora_driver_tasks.ListenersUpdate( requires=[constants.LOADBALANCER, constants.LISTENERS])) delete_hm_flow.add(database_tasks.DeleteHealthMonitorInDB( requires=constants.POOL_ID)) delete_hm_flow.add(database_tasks.DecrementHealthMonitorQuota( requires=constants.HEALTH_MON)) delete_hm_flow.add(database_tasks.MarkLBAndListenersActiveInDB( requires=[constants.LOADBALANCER, constants.LISTENERS])) return delete_hm_flow
def get_delete_l7rule_flow(self): """Create a flow to delete an L7 rule :returns: The flow for deleting an L7 rule """ delete_l7rule_flow = linear_flow.Flow(constants.DELETE_L7RULE_FLOW) delete_l7rule_flow.add( lifecycle_tasks.L7RuleToErrorOnRevertTask(requires=[ constants.L7RULE, constants.LISTENERS, constants.LOADBALANCER ])) delete_l7rule_flow.add( database_tasks.MarkL7RulePendingDeleteInDB( requires=constants.L7RULE)) delete_l7rule_flow.add( model_tasks.DeleteModelObject( rebind={constants.OBJECT: constants.L7RULE})) delete_l7rule_flow.add( amphora_driver_tasks.ListenersUpdate( requires=[constants.LOADBALANCER, constants.LISTENERS])) delete_l7rule_flow.add( database_tasks.DeleteL7RuleInDB(requires=constants.L7RULE)) delete_l7rule_flow.add( database_tasks.MarkL7PolicyActiveInDB(requires=constants.L7POLICY)) delete_l7rule_flow.add( database_tasks.MarkLBAndListenersActiveInDB( requires=[constants.LOADBALANCER, constants.LISTENERS])) return delete_l7rule_flow
def get_create_l7rule_flow(self): """Create a flow to create an L7 rule :returns: The flow for creating an L7 rule """ create_l7rule_flow = linear_flow.Flow(constants.CREATE_L7RULE_FLOW) create_l7rule_flow.add(amphora_driver_tasks.ListenersUpdate( requires=[constants.LOADBALANCER, constants.LISTENERS])) create_l7rule_flow.add(database_tasks.MarkLBAndListenersActiveInDB( requires=[constants.LOADBALANCER, constants.LISTENERS])) return create_l7rule_flow
def get_create_health_monitor_flow(self): """Create a flow to create a health monitor :returns: The flow for creating a health monitor """ create_hm_flow = linear_flow.Flow(constants.CREATE_HEALTH_MONITOR_FLOW) create_hm_flow.add(amphora_driver_tasks.ListenersUpdate( requires=[constants.LOADBALANCER, constants.LISTENERS])) create_hm_flow.add(database_tasks.MarkLBAndListenersActiveInDB( requires=[constants.LOADBALANCER, constants.LISTENERS])) return create_hm_flow
def get_create_listener_flow(self): """Create a flow to create a listener :returns: The flow for creating a listener """ create_listener_flow = linear_flow.Flow(constants.CREATE_LISTENER_FLOW) create_listener_flow.add(amphora_driver_tasks.ListenersUpdate( requires=[constants.LOADBALANCER, constants.LISTENERS])) create_listener_flow.add(network_tasks.UpdateVIP( requires=constants.LOADBALANCER)) create_listener_flow.add(database_tasks. MarkLBAndListenersActiveInDB( requires=[constants.LOADBALANCER, constants.LISTENERS])) return create_listener_flow
def get_update_l7rule_flow(self): """Create a flow to update an L7 rule :returns: The flow for updating an L7 rule """ update_l7rule_flow = linear_flow.Flow(constants.UPDATE_L7RULE_FLOW) update_l7rule_flow.add( model_tasks.UpdateAttributes( rebind={constants.OBJECT: constants.L7RULE}, requires=[constants.UPDATE_DICT])) update_l7rule_flow.add(amphora_driver_tasks.ListenersUpdate( requires=[constants.LOADBALANCER, constants.LISTENERS])) update_l7rule_flow.add(database_tasks.UpdateL7RuleInDB( requires=[constants.L7RULE, constants.UPDATE_DICT])) update_l7rule_flow.add(database_tasks.MarkLBAndListenersActiveInDB( requires=[constants.LOADBALANCER, constants.LISTENERS])) return update_l7rule_flow
def get_delete_pool_flow(self): """Create a flow to delete a pool :returns: The flow for deleting a pool """ delete_pool_flow = linear_flow.Flow(constants.DELETE_POOL_FLOW) delete_pool_flow.add( model_tasks.DeleteModelObject( rebind={constants.OBJECT: constants.POOL})) delete_pool_flow.add( amphora_driver_tasks.ListenersUpdate( requires=[constants.LOADBALANCER, constants.LISTENERS])) delete_pool_flow.add( database_tasks.DeletePoolInDB(requires=constants.POOL)) delete_pool_flow.add( database_tasks.MarkLBAndListenersActiveInDB( requires=[constants.LOADBALANCER, constants.LISTENERS])) return delete_pool_flow
def get_update_listener_flow(self): """Create a flow to update a listener :returns: The flow for updating a listener """ update_listener_flow = linear_flow.Flow(constants.UPDATE_LISTENER_FLOW) update_listener_flow.add( lifecycle_tasks.ListenersToErrorOnRevertTask( requires=[constants.LOADBALANCER, constants.LISTENERS])) update_listener_flow.add( amphora_driver_tasks.ListenersUpdate( requires=[constants.LOADBALANCER, constants.LISTENERS])) update_listener_flow.add( database_tasks.UpdateListenerInDB( requires=[constants.LISTENER, constants.UPDATE_DICT])) update_listener_flow.add( database_tasks.MarkLBAndListenersActiveInDB( requires=[constants.LOADBALANCER, constants.LISTENERS])) return update_listener_flow
def get_create_l7policy_flow(self): """Create a flow to create an L7 policy :returns: The flow for creating an L7 policy """ create_l7policy_flow = linear_flow.Flow(constants.CREATE_L7POLICY_FLOW) create_l7policy_flow.add(lifecycle_tasks.L7PolicyToErrorOnRevertTask( requires=[constants.L7POLICY, constants.LISTENERS, constants.LOADBALANCER])) create_l7policy_flow.add(database_tasks.MarkL7PolicyPendingCreateInDB( requires=constants.L7POLICY)) create_l7policy_flow.add(amphora_driver_tasks.ListenersUpdate( requires=[constants.LOADBALANCER, constants.LISTENERS])) create_l7policy_flow.add(database_tasks.MarkL7PolicyActiveInDB( requires=constants.L7POLICY)) create_l7policy_flow.add(database_tasks.MarkLBAndListenersActiveInDB( requires=[constants.LOADBALANCER, constants.LISTENERS])) return create_l7policy_flow
def get_create_pool_flow(self): """Create a flow to create a pool :returns: The flow for creating a pool """ create_pool_flow = linear_flow.Flow(constants.CREATE_POOL_FLOW) create_pool_flow.add(lifecycle_tasks.PoolToErrorOnRevertTask( requires=[constants.POOL, constants.LISTENERS, constants.LOADBALANCER])) create_pool_flow.add(database_tasks.MarkPoolPendingCreateInDB( requires=constants.POOL)) create_pool_flow.add(amphora_driver_tasks.ListenersUpdate( requires=[constants.LOADBALANCER, constants.LISTENERS])) create_pool_flow.add(database_tasks.MarkPoolActiveInDB( requires=constants.POOL)) create_pool_flow.add(database_tasks.MarkLBAndListenersActiveInDB( requires=[constants.LOADBALANCER, constants.LISTENERS])) return create_pool_flow
def get_create_all_listeners_flow(self): """Create a flow to create all listeners :returns: The flow for creating all listeners """ create_all_listeners_flow = linear_flow.Flow( constants.CREATE_LISTENERS_FLOW) create_all_listeners_flow.add( database_tasks.GetListenersFromLoadbalancer( requires=constants.LOADBALANCER, provides=constants.LISTENERS)) create_all_listeners_flow.add( database_tasks.ReloadLoadBalancer( requires=constants.LOADBALANCER_ID, provides=constants.LOADBALANCER)) create_all_listeners_flow.add( amphora_driver_tasks.ListenersUpdate( requires=[constants.LOADBALANCER, constants.LISTENERS])) create_all_listeners_flow.add( network_tasks.UpdateVIP(requires=constants.LOADBALANCER)) return create_all_listeners_flow
def get_failover_flow(self): """Creates a flow to failover a stale amphora :returns: The flow for amphora failover """ failover_amphora_flow = linear_flow.Flow( constants.FAILOVER_AMPHORA_FLOW) failover_amphora_flow.add( network_tasks.RetrievePortIDsOnAmphoraExceptLBNetwork( requires=constants.AMPHORA, provides=constants.PORTS)) failover_amphora_flow.add( network_tasks.FailoverPreparationForAmphora( requires=constants.AMPHORA)) failover_amphora_flow.add( compute_tasks.ComputeDelete(requires=constants.AMPHORA)) failover_amphora_flow.add( database_tasks.MarkAmphoraDeletedInDB(requires=constants.AMPHORA)) failover_amphora_flow.add( database_tasks.CreateAmphoraInDB(provides=constants.AMPHORA_ID)) failover_amphora_flow.add( database_tasks.GetUpdatedFailoverAmpNetworkDetailsAsList( requires=(constants.AMPHORA_ID, constants.AMPHORA), provides=constants.AMPS_DATA)) if self.REST_AMPHORA_DRIVER: failover_amphora_flow.add( cert_task.GenerateServerPEMTask(provides=constants.SERVER_PEM)) failover_amphora_flow.add( compute_tasks.CertComputeCreate( requires=(constants.AMPHORA_ID, constants.SERVER_PEM), provides=constants.COMPUTE_ID)) else: failover_amphora_flow.add( compute_tasks.ComputeCreate(requires=constants.AMPHORA_ID, provides=constants.COMPUTE_ID)) failover_amphora_flow.add( database_tasks.UpdateAmphoraComputeId( requires=(constants.AMPHORA_ID, constants.COMPUTE_ID))) failover_amphora_flow.add( database_tasks.AssociateFailoverAmphoraWithLBID( requires=(constants.AMPHORA_ID, constants.LOADBALANCER_ID))) failover_amphora_flow.add( database_tasks.MarkAmphoraBootingInDB( requires=(constants.AMPHORA_ID, constants.COMPUTE_ID))) wait_flow = linear_flow.Flow( constants.WAIT_FOR_AMPHORA, retry=retry.Times(CONF.controller_worker.amp_active_retries)) wait_flow.add( compute_tasks.ComputeWait(requires=constants.COMPUTE_ID, provides=constants.COMPUTE_OBJ)) wait_flow.add( database_tasks.UpdateAmphoraInfo(requires=(constants.AMPHORA_ID, constants.COMPUTE_OBJ), provides=constants.AMPHORA)) failover_amphora_flow.add(wait_flow) failover_amphora_flow.add( database_tasks.ReloadAmphora(requires=constants.AMPHORA_ID, provides=constants.FAILOVER_AMPHORA)) failover_amphora_flow.add( amphora_driver_tasks.AmphoraFinalize( rebind={constants.AMPHORA: constants.FAILOVER_AMPHORA}, requires=constants.AMPHORA)) failover_amphora_flow.add( database_tasks.UpdateAmphoraVIPData(requires=constants.AMPS_DATA)) failover_amphora_flow.add( database_tasks.ReloadLoadBalancer( requires=constants.LOADBALANCER_ID, provides=constants.LOADBALANCER)) failover_amphora_flow.add( network_tasks.GetAmphoraeNetworkConfigs( requires=constants.LOADBALANCER, provides=constants.AMPHORAE_NETWORK_CONFIG)) failover_amphora_flow.add( database_tasks.GetListenersFromLoadbalancer( requires=constants.LOADBALANCER, provides=constants.LISTENERS)) failover_amphora_flow.add( database_tasks.GetVipFromLoadbalancer( requires=constants.LOADBALANCER, provides=constants.VIP)) failover_amphora_flow.add( amphora_driver_tasks.ListenersUpdate(requires=(constants.LISTENERS, constants.VIP))) failover_amphora_flow.add( amphora_driver_tasks.AmphoraPostVIPPlug( requires=(constants.LOADBALANCER, constants.AMPHORAE_NETWORK_CONFIG))) failover_amphora_flow.add( network_tasks.GetMemberPorts( rebind={constants.AMPHORA: constants.FAILOVER_AMPHORA}, requires=(constants.LOADBALANCER, constants.AMPHORA), provides=constants.MEMBER_PORTS)) failover_amphora_flow.add( amphora_driver_tasks.AmphoraPostNetworkPlug( rebind={ constants.AMPHORA: constants.FAILOVER_AMPHORA, constants.PORTS: constants.MEMBER_PORTS }, requires=(constants.AMPHORA, constants.PORTS))) failover_amphora_flow.add( amphora_driver_tasks.ListenersStart(requires=(constants.LISTENERS, constants.VIP))) failover_amphora_flow.add( database_tasks.MarkAmphoraAllocatedInDB( rebind={constants.AMPHORA: constants.FAILOVER_AMPHORA}, requires=(constants.AMPHORA, constants.LOADBALANCER_ID))) return failover_amphora_flow
def get_failover_flow(self, role=constants.ROLE_STANDALONE): """Creates a flow to failover a stale amphora :returns: The flow for amphora failover """ failover_amphora_flow = linear_flow.Flow( constants.FAILOVER_AMPHORA_FLOW) failover_amphora_flow.add( network_tasks.RetrievePortIDsOnAmphoraExceptLBNetwork( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA, provides=constants.PORTS)) failover_amphora_flow.add( network_tasks.FailoverPreparationForAmphora( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA)) # Delete the old amphora failover_amphora_flow.add( database_tasks.MarkAmphoraPendingDeleteInDB( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA)) failover_amphora_flow.add( database_tasks.MarkAmphoraHealthBusy( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA)) failover_amphora_flow.add( compute_tasks.ComputeDelete( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA)) failover_amphora_flow.add( database_tasks.DisableAmphoraHealthMonitoring( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA)) failover_amphora_flow.add( database_tasks.MarkAmphoraDeletedInDB( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA)) # Save failed amphora details for later failover_amphora_flow.add( database_tasks.GetAmphoraDetails( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA, provides=constants.AMP_DATA)) # Get a new amphora # Note: Role doesn't matter here. We will update it later. get_amp_subflow = self.get_amphora_for_lb_subflow( prefix=constants.FAILOVER_AMPHORA_FLOW) failover_amphora_flow.add(get_amp_subflow) # Update the new amphora with the failed amphora details failover_amphora_flow.add( database_tasks.UpdateAmpFailoverDetails( requires=(constants.AMPHORA, constants.AMP_DATA))) failover_amphora_flow.add( database_tasks.ReloadLoadBalancer( requires=constants.LOADBALANCER_ID, provides=constants.LOADBALANCER)) failover_amphora_flow.add( network_tasks.GetAmphoraeNetworkConfigs( requires=constants.LOADBALANCER, provides=constants.AMPHORAE_NETWORK_CONFIG)) failover_amphora_flow.add( database_tasks.GetListenersFromLoadbalancer( requires=constants.LOADBALANCER, provides=constants.LISTENERS)) failover_amphora_flow.add( database_tasks.GetVipFromLoadbalancer( requires=constants.LOADBALANCER, provides=constants.VIP)) failover_amphora_flow.add( amphora_driver_tasks.ListenersUpdate( requires=(constants.LOADBALANCER, constants.LISTENERS))) failover_amphora_flow.add( network_tasks.PlugPorts(requires=(constants.AMPHORA, constants.PORTS))) failover_amphora_flow.add( amphora_driver_tasks.AmphoraPostVIPPlug( requires=(constants.LOADBALANCER, constants.AMPHORAE_NETWORK_CONFIG))) failover_amphora_flow.add( network_tasks.GetMemberPorts(requires=(constants.LOADBALANCER, constants.AMPHORA), provides=constants.MEMBER_PORTS)) failover_amphora_flow.add( amphora_driver_tasks.AmphoraPostNetworkPlug( rebind={constants.PORTS: constants.MEMBER_PORTS}, requires=(constants.AMPHORA, constants.PORTS))) # Handle the amphora role and VRRP if necessary if role == constants.ROLE_MASTER: failover_amphora_flow.add( database_tasks.MarkAmphoraMasterInDB( name=constants.MARK_AMP_MASTER_INDB, requires=constants.AMPHORA)) vrrp_subflow = self.get_vrrp_subflow(role) failover_amphora_flow.add(vrrp_subflow) elif role == constants.ROLE_BACKUP: failover_amphora_flow.add( database_tasks.MarkAmphoraBackupInDB( name=constants.MARK_AMP_BACKUP_INDB, requires=constants.AMPHORA)) vrrp_subflow = self.get_vrrp_subflow(role) failover_amphora_flow.add(vrrp_subflow) elif role == constants.ROLE_STANDALONE: failover_amphora_flow.add( database_tasks.MarkAmphoraStandAloneInDB( name=constants.MARK_AMP_STANDALONE_INDB, requires=constants.AMPHORA)) failover_amphora_flow.add( amphora_driver_tasks.ListenersStart( requires=(constants.LOADBALANCER, constants.LISTENERS))) return failover_amphora_flow
def get_failover_flow(self, role=constants.ROLE_STANDALONE, status=constants.AMPHORA_READY): """Creates a flow to failover a stale amphora :returns: The flow for amphora failover """ failover_amphora_flow = linear_flow.Flow( constants.FAILOVER_AMPHORA_FLOW) failover_amphora_flow.add(lifecycle_tasks.AmphoraToErrorOnRevertTask( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA)) # Delete the old amphora failover_amphora_flow.add( database_tasks.MarkAmphoraPendingDeleteInDB( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA)) failover_amphora_flow.add( database_tasks.MarkAmphoraHealthBusy( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA)) failover_amphora_flow.add(compute_tasks.ComputeDelete( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA)) failover_amphora_flow.add(network_tasks.WaitForPortDetach( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA)) failover_amphora_flow.add( database_tasks.DisableAmphoraHealthMonitoring( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA)) failover_amphora_flow.add(database_tasks.MarkAmphoraDeletedInDB( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA)) # If this is an unallocated amp (spares pool), we're done if status != constants.AMPHORA_ALLOCATED: return failover_amphora_flow # Save failed amphora details for later failover_amphora_flow.add( database_tasks.GetAmphoraDetails( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA, provides=constants.AMP_DATA)) # Get a new amphora # Note: Role doesn't matter here. We will update it later. get_amp_subflow = self.get_amphora_for_lb_subflow( prefix=constants.FAILOVER_AMPHORA_FLOW) failover_amphora_flow.add(get_amp_subflow) # Update the new amphora with the failed amphora details failover_amphora_flow.add(database_tasks.UpdateAmpFailoverDetails( requires=(constants.AMPHORA, constants.AMP_DATA))) failover_amphora_flow.add(database_tasks.ReloadLoadBalancer( requires=constants.LOADBALANCER_ID, provides=constants.LOADBALANCER)) failover_amphora_flow.add(network_tasks.GetAmphoraeNetworkConfigs( requires=constants.LOADBALANCER, provides=constants.AMPHORAE_NETWORK_CONFIG)) failover_amphora_flow.add(database_tasks.GetListenersFromLoadbalancer( requires=constants.LOADBALANCER, provides=constants.LISTENERS)) failover_amphora_flow.add(amphora_driver_tasks.ListenersUpdate( requires=(constants.LOADBALANCER, constants.LISTENERS))) # Plug the VIP ports into the new amphora failover_amphora_flow.add(network_tasks.PlugVIPPort( requires=(constants.AMPHORA, constants.AMPHORAE_NETWORK_CONFIG))) failover_amphora_flow.add(amphora_driver_tasks.AmphoraPostVIPPlug( requires=(constants.AMPHORA, constants.LOADBALANCER, constants.AMPHORAE_NETWORK_CONFIG))) # Plug the member networks into the new amphora failover_amphora_flow.add(network_tasks.CalculateDelta( requires=constants.LOADBALANCER, provides=constants.DELTAS)) failover_amphora_flow.add(network_tasks.HandleNetworkDeltas( requires=constants.DELTAS, provides=constants.ADDED_PORTS)) failover_amphora_flow.add(amphora_driver_tasks.AmphoraePostNetworkPlug( requires=(constants.LOADBALANCER, constants.ADDED_PORTS))) # Handle the amphora role and VRRP if necessary if role == constants.ROLE_MASTER: failover_amphora_flow.add(database_tasks.MarkAmphoraMasterInDB( name=constants.MARK_AMP_MASTER_INDB, requires=constants.AMPHORA)) vrrp_subflow = self.get_vrrp_subflow(role) failover_amphora_flow.add(vrrp_subflow) elif role == constants.ROLE_BACKUP: failover_amphora_flow.add(database_tasks.MarkAmphoraBackupInDB( name=constants.MARK_AMP_BACKUP_INDB, requires=constants.AMPHORA)) vrrp_subflow = self.get_vrrp_subflow(role) failover_amphora_flow.add(vrrp_subflow) elif role == constants.ROLE_STANDALONE: failover_amphora_flow.add( database_tasks.MarkAmphoraStandAloneInDB( name=constants.MARK_AMP_STANDALONE_INDB, requires=constants.AMPHORA)) failover_amphora_flow.add(amphora_driver_tasks.ListenersStart( requires=(constants.LOADBALANCER, constants.LISTENERS))) return failover_amphora_flow
def get_failover_flow(self, role=constants.ROLE_STANDALONE, load_balancer_id=None): """Creates a flow to failover a stale amphora :returns: The flow for amphora failover """ failover_amphora_flow = linear_flow.Flow( constants.FAILOVER_AMPHORA_FLOW) failover_amphora_flow.add( lifecycle_tasks.AmphoraToErrorOnRevertTask( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA)) # Note: It seems intuitive to boot an amphora prior to deleting # the old amphora, however this is a complicated issue. # If the target host (due to anit-affinity) is resource # constrained, this will fail where a post-delete will # succeed. Since this is async with the API it would result # in the LB ending in ERROR though the amps are still alive. # Consider in the future making this a complicated # try-on-failure-retry flow, or move upgrade failovers to be # synchronous with the API. For now spares pool and act/stdby # will mitigate most of this delay. # Delete the old amphora failover_amphora_flow.add( database_tasks.MarkAmphoraPendingDeleteInDB( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA)) failover_amphora_flow.add( database_tasks.MarkAmphoraHealthBusy( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA)) failover_amphora_flow.add( compute_tasks.ComputeDelete( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA)) failover_amphora_flow.add( network_tasks.WaitForPortDetach( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA)) failover_amphora_flow.add( database_tasks.MarkAmphoraDeletedInDB( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA)) # If this is an unallocated amp (spares pool), we're done if not load_balancer_id: failover_amphora_flow.add( database_tasks.DisableAmphoraHealthMonitoring( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA)) return failover_amphora_flow # Save failed amphora details for later failover_amphora_flow.add( database_tasks.GetAmphoraDetails( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA, provides=constants.AMP_DATA)) # Get a new amphora # Note: Role doesn't matter here. We will update it later. get_amp_subflow = self.get_amphora_for_lb_subflow( prefix=constants.FAILOVER_AMPHORA_FLOW) failover_amphora_flow.add(get_amp_subflow) # Update the new amphora with the failed amphora details failover_amphora_flow.add( database_tasks.UpdateAmpFailoverDetails( requires=(constants.AMPHORA, constants.AMP_DATA))) # Update the data stored in the flow from the database failover_amphora_flow.add( database_tasks.ReloadLoadBalancer( requires=constants.LOADBALANCER_ID, provides=constants.LOADBALANCER)) failover_amphora_flow.add( database_tasks.ReloadAmphora(requires=constants.AMPHORA_ID, provides=constants.AMPHORA)) # Prepare to reconnect the network interface(s) failover_amphora_flow.add( network_tasks.GetAmphoraeNetworkConfigs( requires=constants.LOADBALANCER, provides=constants.AMPHORAE_NETWORK_CONFIG)) failover_amphora_flow.add( database_tasks.GetListenersFromLoadbalancer( requires=constants.LOADBALANCER, provides=constants.LISTENERS)) failover_amphora_flow.add( amphora_driver_tasks.ListenersUpdate( requires=(constants.LOADBALANCER, constants.LISTENERS))) # Plug the VIP ports into the new amphora failover_amphora_flow.add( network_tasks.PlugVIPPort( requires=(constants.AMPHORA, constants.AMPHORAE_NETWORK_CONFIG))) failover_amphora_flow.add( amphora_driver_tasks.AmphoraPostVIPPlug( requires=(constants.AMPHORA, constants.LOADBALANCER, constants.AMPHORAE_NETWORK_CONFIG))) # Plug the member networks into the new amphora failover_amphora_flow.add( network_tasks.CalculateDelta(requires=constants.LOADBALANCER, provides=constants.DELTAS)) failover_amphora_flow.add( network_tasks.HandleNetworkDeltas(requires=constants.DELTAS, provides=constants.ADDED_PORTS)) failover_amphora_flow.add( amphora_driver_tasks.AmphoraePostNetworkPlug( requires=(constants.LOADBALANCER, constants.ADDED_PORTS))) # Handle the amphora role and VRRP if necessary if role == constants.ROLE_MASTER: failover_amphora_flow.add( database_tasks.MarkAmphoraMasterInDB( name=constants.MARK_AMP_MASTER_INDB, requires=constants.AMPHORA)) vrrp_subflow = self.get_vrrp_subflow(role) failover_amphora_flow.add(vrrp_subflow) elif role == constants.ROLE_BACKUP: failover_amphora_flow.add( database_tasks.MarkAmphoraBackupInDB( name=constants.MARK_AMP_BACKUP_INDB, requires=constants.AMPHORA)) vrrp_subflow = self.get_vrrp_subflow(role) failover_amphora_flow.add(vrrp_subflow) elif role == constants.ROLE_STANDALONE: failover_amphora_flow.add( database_tasks.MarkAmphoraStandAloneInDB( name=constants.MARK_AMP_STANDALONE_INDB, requires=constants.AMPHORA)) failover_amphora_flow.add( amphora_driver_tasks.ListenersStart( requires=(constants.LOADBALANCER, constants.LISTENERS))) failover_amphora_flow.add( database_tasks.DisableAmphoraHealthMonitoring( rebind={constants.AMPHORA: constants.FAILED_AMPHORA}, requires=constants.AMPHORA)) return failover_amphora_flow
def get_batch_update_members_flow(self, old_members, new_members, updated_members): """Create a flow to batch update members :returns: The flow for batch updating members """ batch_update_members_flow = linear_flow.Flow( constants.BATCH_UPDATE_MEMBERS_FLOW) unordered_members_flow = unordered_flow.Flow( constants.UNORDERED_MEMBER_UPDATES_FLOW) unordered_members_active_flow = unordered_flow.Flow( constants.UNORDERED_MEMBER_ACTIVE_FLOW) # Delete old members unordered_members_flow.add( lifecycle_tasks.MembersToErrorOnRevertTask( inject={constants.MEMBERS: old_members}, name='{flow}-deleted'.format( flow=constants.MEMBER_TO_ERROR_ON_REVERT_FLOW))) for m in old_members: unordered_members_flow.add( model_tasks.DeleteModelObject( inject={constants.OBJECT: m}, name='{flow}-{id}'.format( id=m.id, flow=constants.DELETE_MODEL_OBJECT_FLOW))) unordered_members_flow.add( database_tasks.DeleteMemberInDB( inject={constants.MEMBER: m}, name='{flow}-{id}'.format( id=m.id, flow=constants.DELETE_MEMBER_INDB))) unordered_members_flow.add( database_tasks.DecrementMemberQuota( inject={constants.MEMBER: m}, name='{flow}-{id}'.format( id=m.id, flow=constants.DECREMENT_MEMBER_QUOTA_FLOW))) # Create new members unordered_members_flow.add( lifecycle_tasks.MembersToErrorOnRevertTask( inject={constants.MEMBERS: new_members}, name='{flow}-created'.format( flow=constants.MEMBER_TO_ERROR_ON_REVERT_FLOW))) for m in new_members: unordered_members_active_flow.add( database_tasks.MarkMemberActiveInDB( inject={constants.MEMBER: m}, name='{flow}-{id}'.format( id=m.id, flow=constants.MARK_MEMBER_ACTIVE_INDB))) # Update existing members unordered_members_flow.add( lifecycle_tasks.MembersToErrorOnRevertTask( # updated_members is a list of (obj, dict), only pass `obj` inject={constants.MEMBERS: [m[0] for m in updated_members]}, name='{flow}-updated'.format( flow=constants.MEMBER_TO_ERROR_ON_REVERT_FLOW))) for m, um in updated_members: um.pop('id', None) unordered_members_flow.add( model_tasks.UpdateAttributes( inject={ constants.OBJECT: m, constants.UPDATE_DICT: um }, name='{flow}-{id}'.format( id=m.id, flow=constants.UPDATE_ATTRIBUTES_FLOW))) unordered_members_flow.add( database_tasks.UpdateMemberInDB( inject={ constants.MEMBER: m, constants.UPDATE_DICT: um }, name='{flow}-{id}'.format( id=m.id, flow=constants.UPDATE_MEMBER_INDB))) unordered_members_active_flow.add( database_tasks.MarkMemberActiveInDB( inject={constants.MEMBER: m}, name='{flow}-{id}'.format( id=m.id, flow=constants.MARK_MEMBER_ACTIVE_INDB))) batch_update_members_flow.add(unordered_members_flow) # Done, do real updates batch_update_members_flow.add( network_tasks.CalculateDelta(requires=constants.LOADBALANCER, provides=constants.DELTAS)) batch_update_members_flow.add( network_tasks.HandleNetworkDeltas(requires=constants.DELTAS, provides=constants.ADDED_PORTS)) batch_update_members_flow.add( amphora_driver_tasks.AmphoraePostNetworkPlug( requires=(constants.LOADBALANCER, constants.ADDED_PORTS))) # Update the Listener (this makes the changes active on the Amp) batch_update_members_flow.add( amphora_driver_tasks.ListenersUpdate( requires=(constants.LOADBALANCER, constants.LISTENERS))) # Mark all the members ACTIVE here, then pool then LB/Listeners batch_update_members_flow.add(unordered_members_active_flow) batch_update_members_flow.add( database_tasks.MarkPoolActiveInDB(requires=constants.POOL)) batch_update_members_flow.add( database_tasks.MarkLBAndListenersActiveInDB( requires=(constants.LOADBALANCER, constants.LISTENERS))) return batch_update_members_flow