def setUp(self): """ Set up a desired group state to use for desired, so that serializing objects can be tested. """ self.state = DesiredServerGroupState(server_config='config', capacity=1)
def test_no_lbs(self): """ When no loadBalancers are specified, the returned DesiredServerGroupState has an empty mapping for desired_lbs. If no draining_timeout is provided, returned DesiredServerGroupState has draining_timeout as 0.0 """ server_config = {'name': 'test', 'flavorRef': 'f'} lc = {'args': {'server': server_config}} expected_server_config = { 'server': { 'name': 'test', 'flavorRef': 'f', 'metadata': { 'rax:auto_scaling_group_id': 'uuid', 'rax:autoscale:group:id': 'uuid'}}} state = get_desired_server_group_state('uuid', lc, 2) self.assertEqual( state, DesiredServerGroupState( server_config=expected_server_config, capacity=2, desired_lbs=pset(), draining_timeout=0.0)) self.assert_server_config_hashable(state)
def test_convert(self): """ An Otter launch config a :obj:`DesiredServerGroupState`, ignoring extra config information. """ server_config = {'name': 'test', 'flavorRef': 'f'} lc = {'args': {'server': server_config, 'loadBalancers': [ {'loadBalancerId': 23, 'port': 80, 'whatsit': 'invalid'}, {'loadBalancerId': 23, 'port': 90}, {'loadBalancerId': 23, 'type': 'RackConnectV3'}, {'loadBalancerId': '12', 'type': 'RackConnectV3'}], 'draining_timeout': 35}} expected_server_config = { 'server': { 'name': 'test', 'flavorRef': 'f', 'metadata': { 'rax:auto_scaling_group_id': 'uuid', 'rax:autoscale:group:id': 'uuid', 'rax:autoscale:lb:CloudLoadBalancer:23': json.dumps( [{"port": 80}, {"port": 90}]), 'rax:autoscale:lb:RackConnectV3:23': '', 'rax:autoscale:lb:RackConnectV3:12': '' } } } state = get_desired_server_group_state('uuid', lc, 2) self.assertEqual( state, DesiredServerGroupState( server_config=expected_server_config, capacity=2, desired_lbs=pset([ CLBDescription(lb_id='23', port=80), CLBDescription(lb_id='23', port=90), RCv3Description(lb_id='23'), RCv3Description(lb_id='12')]), draining_timeout=35.0)) self.assert_server_config_hashable(state)
def test_capacity_closer_to_desired_when_scaling_down(self): """ If the capacity moves closer to the desired, progress has been made. """ previous_state = GroupState( servers=self._create_servers(4), lb_connections=pset([]) ) current_state = GroupState( servers=self._create_servers(2), lb_connections=pset([]) ) desired_state = DesiredServerGroupState( server_config=pmap(), capacity=1, ) progress = measure_progress( previous_state, current_state, desired_state) self.assertEqual(progress, 2)
def test_overshoot(self): """ When overshooting the desired capacity (group was below desired, and is now above desired), no progress was made. """ previous_state = GroupState( servers=self._create_servers(4), lb_connections=pset([]) ) current_state = GroupState( servers=self._create_servers(6), lb_connections=pset([]) ) desired_state = DesiredServerGroupState( server_config=pmap(), capacity=5, ) self.assertRaises( OvershootError, measure_progress, previous_state, current_state, desired_state)
def test_reaping_errored_servers(self): """ Errored servers are removed; no progress is made. """ previous_state = GroupState( servers=(self._create_servers(1, state=ServerState.ACTIVE) | self._create_servers(2, state=ServerState.ERROR)), lb_connections=pset([]) ) current_state = GroupState( servers=(self._create_servers(1, state=ServerState.ACTIVE)), lb_connections=pset([]) ) desired_state = DesiredServerGroupState( server_config=pmap(), capacity=5, ) progress = measure_progress( previous_state, current_state, desired_state) self.assertEqual(progress, 0)
def test_servers_going_from_build_to_error(self): """ When some servers go from build to error, no progress was made. """ previous_state = GroupState( servers=self._create_servers(3, state=ServerState.BUILD), lb_connections=pset([]) ) current_state = GroupState( servers=(self._create_servers(1, state=ServerState.ACTIVE) | self._create_servers(2, state=ServerState.ERROR)), lb_connections=pset([]) ) desired_state = DesiredServerGroupState( server_config=pmap(), capacity=5, ) progress = measure_progress( previous_state, current_state, desired_state) self.assertEqual(progress, 0)
def test_building_servers_towards_desired_capacity(self): """ When some servers are being built, which would put us closer to the desired capacity, progress is being made. """ previous_state = GroupState( servers=self._create_servers(2), lb_connections=pset([]) ) current_state = GroupState( servers=(self._create_servers(2, state=ServerState.ACTIVE) | self._create_servers(2, state=ServerState.BUILD)), lb_connections=pset([]) ) desired_state = DesiredServerGroupState( server_config=pmap(), capacity=5, ) progress = measure_progress( previous_state, current_state, desired_state) self.assertEqual(progress, 2)
def get_desired_server_group_state(group_id, launch_config, desired): """ Create a :obj:`DesiredServerGroupState` from a group details. :param str group_id: The group ID :param dict launch_config: Group's launch config as per :obj:`otter.json_schema.group_schemas.launch_config` :param int desired: Group's desired capacity """ lbs = freeze(launch_config['args'].get('loadBalancers', [])) lbs = json_to_LBConfigs(lbs) server_lc = prepare_server_launch_config( group_id, freeze({'server': launch_config['args']['server']}), lbs) draining = float(launch_config["args"].get("draining_timeout", 0.0)) desired_state = DesiredServerGroupState( server_config=server_lc, capacity=desired, desired_lbs=lbs, draining_timeout=draining) return desired_state
def test_servers_going_from_build_to_error_with_reaping(self): """ When some servers go from build to error, no progress was made. That works correctly even if some of the errored machines get reaped in the mean while. """ previous_state = GroupState( servers=self._create_servers(3, state=ServerState.BUILD), lb_connections=pset([]) ) current_state = GroupState( servers=(self._create_servers(1, state=ServerState.ACTIVE) | self._create_servers(1, state=ServerState.ERROR)), lb_connections=pset([]) ) desired_state = DesiredServerGroupState( server_config=pmap(), capacity=5, ) progress = measure_progress( previous_state, current_state, desired_state) self.assertEqual(progress, 0)