def test_draining_server_can_be_deleted_if_all_lbs_can_be_removed(self): """ If draining server can be removed from all the load balancers, the server can be deleted. """ self.assertEqual( converge( DesiredGroupState(server_config={}, capacity=0), set([server('abc', state=ServerState.ACTIVE, metadata=dict([DRAINING_METADATA]), servicenet_address='1.1.1.1', desired_lbs=s(self.clb_desc, self.rcv3_desc))]), set([CLBNode(node_id='1', address='1.1.1.1', description=copy_clb_desc( self.clb_desc, condition=CLBNodeCondition.DRAINING)), RCv3Node(node_id='2', cloud_server_id='abc', description=self.rcv3_desc)]), 0), pbag([ DeleteServer(server_id='abc'), RemoveNodesFromCLB(lb_id='1', node_ids=s('1')), BulkRemoveFromRCv3(lb_node_pairs=s( (self.rcv3_desc.lb_id, 'abc'))) ]))
def test_clean_up_deleted_servers_with_lb_nodes(self): """ If a server has been deleted, we want to remove any dangling LB nodes referencing the server. """ self.assertEqual( converge( DesiredGroupState(server_config={}, capacity=0), set([server('abc', ServerState.DELETED, servicenet_address='1.1.1.1', desired_lbs=s(CLBDescription(lb_id='5', port=80), CLBDescription(lb_id='5', port=8080), RCv3Description(lb_id='6')))]), set([CLBNode(address='1.1.1.1', node_id='3', description=CLBDescription(lb_id='5', port=80)), CLBNode(address='1.1.1.1', node_id='5', description=CLBDescription(lb_id='5', port=8080)), RCv3Node(node_id='123', cloud_server_id='abc', description=RCv3Description(lb_id='6'))]), 0), pbag([ RemoveNodesFromCLB(lb_id='5', node_ids=s('3')), RemoveNodesFromCLB(lb_id='5', node_ids=s('5')), BulkRemoveFromRCv3(lb_node_pairs=s(('6', 'abc'))), ]))
def test_plan(self): """An optimized plan is returned. Steps are limited.""" desc = CLBDescription(lb_id='5', port=80) desired_lbs = s(desc) desired_group_state = DesiredGroupState( server_config={}, capacity=20, desired_lbs=desired_lbs) result = plan( desired_group_state, set([server('server1', state=ServerState.ACTIVE, servicenet_address='1.1.1.1', desired_lbs=desired_lbs), server('server2', state=ServerState.ACTIVE, servicenet_address='1.2.3.4', desired_lbs=desired_lbs)]), set(), 0, build_timeout=3600) self.assertEqual( result, pbag([ AddNodesToCLB( lb_id='5', address_configs=s(('1.1.1.1', desc), ('1.2.3.4', desc)) )] + [CreateServer(server_config=pmap({}))] * 10))
def test_delete_error_state_servers_with_lb_nodes(self): """ If a server we created enters error state and it is attached to one or more load balancers, it will be removed from its load balancers as well as get deleted. (Tests that error state servers are not excluded from converging load balancer state.) """ self.assertEqual( converge( DesiredGroupState(server_config={}, capacity=1), set([server('abc', ServerState.ERROR, servicenet_address='1.1.1.1', desired_lbs=s(CLBDescription(lb_id='5', port=80), CLBDescription(lb_id='5', port=8080), RCv3Description(lb_id='6')))]), set([CLBNode(address='1.1.1.1', node_id='3', description=CLBDescription(lb_id='5', port=80)), CLBNode(address='1.1.1.1', node_id='5', description=CLBDescription(lb_id='5', port=8080)), RCv3Node(node_id='123', cloud_server_id='abc', description=RCv3Description(lb_id='6'))]), 0), pbag([ DeleteServer(server_id='abc'), RemoveNodesFromCLB(lb_id='5', node_ids=s('3')), RemoveNodesFromCLB(lb_id='5', node_ids=s('5')), BulkRemoveFromRCv3(lb_node_pairs=s(('6', 'abc'))), CreateServer(server_config=pmap()), ]))
def test_same_clb_multiple_ports(self): """ It's possible to have the same cloud load balancer using multiple ports on the host. (use case: running multiple single-threaded server processes on a machine) """ desired = s(CLBDescription(lb_id='5', port=8080), CLBDescription(lb_id='5', port=8081)) current = [] self.assertEqual( converge( DesiredGroupState(server_config={}, capacity=1), set([server('abc', ServerState.ACTIVE, servicenet_address='1.1.1.1', desired_lbs=desired)]), set(current), 0), pbag([ AddNodesToCLB( lb_id='5', address_configs=s(('1.1.1.1', CLBDescription(lb_id='5', port=8080)))), AddNodesToCLB( lb_id='5', address_configs=s(('1.1.1.1', CLBDescription(lb_id='5', port=8081)))) ]))
def test_converge_active_servers_ignores_servers_to_be_deleted(self): """ Only servers in active that are not being deleted will have their load balancers converged. """ desc = CLBDescription(lb_id='5', port=80) desired_lbs = s(desc) self.assertEqual( converge( DesiredGroupState(server_config={}, capacity=1, desired_lbs=desired_lbs), set([server('abc', ServerState.ACTIVE, servicenet_address='1.1.1.1', created=0, desired_lbs=desired_lbs), server('bcd', ServerState.ACTIVE, servicenet_address='2.2.2.2', created=1, desired_lbs=desired_lbs)]), set(), 0), pbag([ DeleteServer(server_id='abc'), AddNodesToCLB( lb_id='5', address_configs=s(('2.2.2.2', desc))) ]))
def test_active_server_is_drained_if_not_all_lbs_can_be_removed(self): """ If an active server to be deleted cannot be removed from all the load balancers, it is set to draining state and all the nodes are set to draining condition. """ self.assertEqual( converge( DesiredGroupState(server_config={}, capacity=0, draining_timeout=10.0), set([server('abc', state=ServerState.ACTIVE, servicenet_address='1.1.1.1', desired_lbs=s(self.clb_desc, self.rcv3_desc))]), set([CLBNode(node_id='1', address='1.1.1.1', description=self.clb_desc), RCv3Node(node_id='2', cloud_server_id='abc', description=self.rcv3_desc)]), 0), pbag([ ChangeCLBNode(lb_id='1', node_id='1', weight=1, condition=CLBNodeCondition.DRAINING, type=CLBNodeType.PRIMARY), SetMetadataItemOnServer(server_id='abc', key=DRAINING_METADATA[0], value=DRAINING_METADATA[1]), BulkRemoveFromRCv3(lb_node_pairs=s( (self.rcv3_desc.lb_id, 'abc'))) ]))
def __init__( self, attrs: Optional[Iterable[Attr]] = None, props: Optional[Iterable[Prop]] = None, ): self.attrs = s() if attrs is None else PSet(attrs) self.props = s() if props is None else PSet(props)
def test_filters_clb_types(self): """ Only one CLB step is returned per CLB """ steps = pbag([ AddNodesToCLB( lb_id='5', address_configs=s(('1.1.1.1', CLBDescription(lb_id='5', port=80)))), RemoveNodesFromCLB(lb_id='5', node_ids=s('1')), # Unoptimizable step CreateServer(server_config=pmap({})), ]) # returned steps could be pbag of any of the 2 lists below depending # on how `one_clb_step` iterates over the steps. Since it is pbag the # order of elements is not guaranteed list1 = [ AddNodesToCLB( lb_id='5', address_configs=s( ('1.1.1.1', CLBDescription(lb_id='5', port=80)))), CreateServer(server_config=pmap({})) ] list2 = [ RemoveNodesFromCLB(lb_id='5', node_ids=s('1')), CreateServer(server_config=pmap({})) ] self.assertEqual( matches(MatchesAny(Equals(pbag(list1)), Equals(pbag(list2)))), optimize_steps(steps) )
def test_filters_clb_types(self): """ Only one CLB step is returned per CLB """ steps = pbag([ AddNodesToCLB(lb_id='5', address_configs=s( ('1.1.1.1', CLBDescription(lb_id='5', port=80)))), RemoveNodesFromCLB(lb_id='5', node_ids=s('1')), # Unoptimizable step CreateServer(server_config=pmap({})), ]) # returned steps could be pbag of any of the 2 lists below depending # on how `one_clb_step` iterates over the steps. Since it is pbag the # order of elements is not guaranteed list1 = [ AddNodesToCLB(lb_id='5', address_configs=s( ('1.1.1.1', CLBDescription(lb_id='5', port=80)))), CreateServer(server_config=pmap({})) ] list2 = [ RemoveNodesFromCLB(lb_id='5', node_ids=s('1')), CreateServer(server_config=pmap({})) ] self.assertEqual( matches(MatchesAny(Equals(pbag(list1)), Equals(pbag(list2)))), optimize_steps(steps))
def test_optimize_clb_adds_maintain_unique_ports(self): """ Multiple ports can be specified for the same address and LB ID when adding to a CLB. """ steps = pbag([ AddNodesToCLB( lb_id='5', address_configs=s(('1.1.1.1', CLBDescription(lb_id='5', port=80)))), AddNodesToCLB( lb_id='5', address_configs=s(('1.1.1.1', CLBDescription(lb_id='5', port=8080))))]) self.assertEqual( optimize_steps(steps), pbag([ AddNodesToCLB( lb_id='5', address_configs=s( ('1.1.1.1', CLBDescription(lb_id='5', port=80)), ('1.1.1.1', CLBDescription(lb_id='5', port=8080))))]))
def __init__(self, contents=None, relationships=None, relationship_registry=None): self.contents = contents or s() self.relationships = relationships or s() self.relationship_registry = relationship_registry
def test_optimize_clb_adds_maintain_unique_ports(self): """ Multiple ports can be specified for the same address and LB ID when adding to a CLB. """ steps = pbag([ AddNodesToCLB(lb_id='5', address_configs=s( ('1.1.1.1', CLBDescription(lb_id='5', port=80)))), AddNodesToCLB(lb_id='5', address_configs=s( ('1.1.1.1', CLBDescription(lb_id='5', port=8080)))) ]) self.assertEqual( optimize_steps(steps), pbag([ AddNodesToCLB( lb_id='5', address_configs=s( ('1.1.1.1', CLBDescription(lb_id='5', port=80)), ('1.1.1.1', CLBDescription(lb_id='5', port=8080)))) ]))
def test_add_to_lb(self): """ If a desired LB config is not in the set of current configs, `converge_lb_state` returns the relevant adding-to-load-balancer steps (:class:`AddNodesToCLB` in the case of CLB, :class:`BulkAddToRCv3` in the case of RCv3). """ clb_desc = CLBDescription(lb_id='5', port=80) rcv3_desc = RCv3Description( lb_id='c6fe49fa-114a-4ea4-9425-0af8b30ff1e7') self.assertEqual( converge( DesiredGroupState(server_config={}, capacity=1), set([server('abc', ServerState.ACTIVE, servicenet_address='1.1.1.1', desired_lbs=s(clb_desc, rcv3_desc))]), set(), 0), pbag([ AddNodesToCLB( lb_id='5', address_configs=s(('1.1.1.1', clb_desc))), BulkAddToRCv3( lb_node_pairs=s( ('c6fe49fa-114a-4ea4-9425-0af8b30ff1e7', 'abc'))) ]))
def test_evolver_simple_remove(): x = s(1, 2, 3) e = x.evolver() e.remove(2) x2 = e.persistent() assert x2 == s(1, 3) assert x == s(1, 2, 3)
def make_border( points: np.ndarray, edges: Complex ) -> Tuple[np.ndarray, Complex, Complex, PSet[Cycle], PSet[Cycle]]: def first_index(array: np.ndarray, value: np.ndarray) -> float: return next(i for i, _ in enumerate(array) if np.linalg.norm(value - _) < EPSILON) first_index_points = partial(first_index, points) corners = v(v(-0.5, 0.5), v(-0.5, -0.5), v(0.5, -0.5), v(0.5, 0.5)) ul, dl, dr, ur = pipe(corners, map(np.array), map(first_index_points)) max_ind = len(points) cul = max_ind cdl = max_ind + 1 cdr = max_ind + 2 cur = max_ind + 3 left_c = v(ul, cul, cdl, dl) right_c = v(dr, cdr, cur, ur) down_c = v(dl, cdl, cdr, dr) up_c = v(ur, cur, cul, ul) red_base_cs = s(left_c, right_c) blue_base_cs = s(up_c, down_c) def border_edges(pts: np.ndarray, es: Complex, coord: int, side: float) -> Complex: return pset(edge for edge in es if all( np.linalg.norm(pts[vert][coord] - side) < EPSILON for vert in edge)) border_edges_from_square_side = partial(border_edges, points, edges) left_faces = faces_from_edges( border_edges_from_square_side(0, -0.5) | outer_edges_from_cycle(left_c)) right_faces = faces_from_edges( border_edges_from_square_side(0, 0.5) | outer_edges_from_cycle(right_c)) down_faces = faces_from_edges( border_edges_from_square_side(1, -0.5) | outer_edges_from_cycle(down_c)) up_faces = faces_from_edges( border_edges_from_square_side(1, 0.5) | outer_edges_from_cycle(up_c)) red_base = closure(left_faces | right_faces) blue_base = closure(down_faces | up_faces) border_points = np.array(corners) * BORDER_SCALE aug_points = np.concatenate((points, border_points)) return aug_points, blue_base, red_base, blue_base_cs, red_base_cs
def test_evolver_simple_add(): x = s(1, 2, 3) e = x.evolver() assert not e.is_dirty() e.add(4) assert e.is_dirty() x2 = e.persistent() assert not e.is_dirty() assert x2 == s(1, 2, 3, 4) assert x == s(1, 2, 3)
def test_all_clb_changes_together(self): """ Given all possible combination of clb load balancer states and timeouts, ensure function produces the right set of step for all of them. """ clb_descs = [CLBDescription(lb_id='1', port=80), CLBDescription(lb_id='2', port=80), CLBDescription(lb_id='3', port=80), CLBDescription(lb_id='4', port=80), CLBDescription(lb_id='5', port=80)] clb_nodes = [ # enabled, should be drained CLBNode(node_id='1', address=self.address, description=clb_descs[0]), # disabled, should be removed CLBNode(node_id='2', address=self.address, description=copy_clb_desc( clb_descs[1], condition=CLBNodeCondition.DISABLED)), # draining, still connections, should be ignored CLBNode(node_id='3', address='1.1.1.1', description=copy_clb_desc( clb_descs[2], condition=CLBNodeCondition.DRAINING), connections=3, drained_at=5.0), # draining, no connections, should be removed CLBNode(node_id='4', address='1.1.1.1', description=copy_clb_desc( clb_descs[3], condition=CLBNodeCondition.DRAINING), connections=0, drained_at=5.0), # draining, timeout exired, should be removed CLBNode(node_id='5', address='1.1.1.1', description=copy_clb_desc( clb_descs[4], condition=CLBNodeCondition.DRAINING), connections=10, drained_at=0.0)] clb_steps = [ ChangeCLBNode(lb_id='1', node_id='1', weight=1, condition=CLBNodeCondition.DRAINING, type=CLBNodeType.PRIMARY), RemoveNodesFromCLB(lb_id='2', node_ids=s('2')), RemoveNodesFromCLB(lb_id='4', node_ids=s('4')), RemoveNodesFromCLB(lb_id='5', node_ids=s('5')), ] self.assert_converge_clb_steps( clb_descs=clb_descs, clb_nodes=clb_nodes, clb_steps=clb_steps, draining_timeout=10.0, now=10)
def test_supports_set_comparisons(): s1 = s(1, 2, 3) s3 = s(1, 2) s4 = s(1, 2, 3) assert s(1, 2, 3, 3, 5) == s(1, 2, 3, 5) assert s1 != s3 assert s3 < s1 assert s3 <= s1 assert s3 <= s4 assert s1 > s3 assert s1 >= s3 assert s4 >= s3
def test_supports_set_operations(): s1 = pset([1, 2, 3]) s2 = pset([3, 4, 5]) assert s1 | s2 == s(1, 2, 3, 4, 5) assert s1.union(s2) == s1 | s2 assert s1 & s2 == s(3) assert s1.intersection(s2) == s1 & s2 assert s1 - s2 == s(1, 2) assert s1.difference(s2) == s1 - s2 assert s1 ^ s2 == s(1, 2, 4, 5) assert s1.symmetric_difference(s2) == s1 ^ s2
def setUp(self): self.tenant_id = 'tenant-id' self.group_id = 'group-id' self.state = GroupState(self.tenant_id, self.group_id, 'group-name', {}, {}, None, {}, False, ScalingGroupStatus.ACTIVE, desired=2) self.group = mock_group(self.state, self.tenant_id, self.group_id) self.lc = {'args': {'server': {'name': 'foo'}, 'loadBalancers': []}} self.desired_lbs = s(CLBDescription(lb_id='23', port=80)) self.servers = ( server('a', ServerState.ACTIVE, servicenet_address='10.0.0.1', desired_lbs=self.desired_lbs, links=freeze([{'href': 'link1', 'rel': 'self'}])), server('b', ServerState.ACTIVE, servicenet_address='10.0.0.2', desired_lbs=self.desired_lbs, links=freeze([{'href': 'link2', 'rel': 'self'}])) ) self.state_active = {} self.cache = [thaw(self.servers[0].json), thaw(self.servers[1].json)] self.gsgi = GetScalingGroupInfo(tenant_id='tenant-id', group_id='group-id') self.manifest = { # Many details elided! 'state': self.state, 'launchConfiguration': self.lc, } self.gsgi_result = (self.group, self.manifest) self.now = datetime(1970, 1, 1)
def hello(): number_nodes = int(request.args.get('nodes', 6)) identity = uuid.uuid1().hex point_map = graphs.generate_point_map(number_nodes) edges = graphs.no_interesctions(point_map) domain = s('red', 'green', 'blue', 'purple') nodes = [ Node(id=ix, point=y, color=None, domain=domain) for ix, y in point_map.items() ] problem = Graph(edges=edges, nodes=dict([(node.id, node) for node in nodes])) solver = BacktrackSolver() solution = solver.external_backtrack(problem) solutions[identity] = solution return render_template("hello.html.j2", identity=identity, runtime=solver.runtime, backtrack_calls=solver.backtrack_calls, constraint_tests=solver.constraint_tests, failed_node_choice=solver.failed_node_choice)
class Piece(object): """ A piece that moves to explicit static squares. """ black_character = u" " white_character = u" " _capturable = attr.ib(default=s()) _reachable = attr.ib(default=s()) def capturable_from(self, square): return self._capturable def reachable_from(self, square): return self._reachable
def composition(self, relation): new_relation = s() for i in self.relation: for j in relation: if i[1] == j[0]: new_relation = new_relation.add((i[0], j[1])) return Relation(self.set, new_relation)
def test_change_lb_node(self): """ If a desired CLB mapping is in the set of current configs, but the configuration is wrong, `converge_lb_state` returns a :class:`ChangeCLBNode` object. RCv3 nodes cannot be changed - they are either right or wrong. """ clb_desc = CLBDescription(lb_id='5', port=80) rcv3_desc = RCv3Description( lb_id='c6fe49fa-114a-4ea4-9425-0af8b30ff1e7') current = [CLBNode(node_id='123', address='1.1.1.1', description=copy_clb_desc(clb_desc, weight=5)), RCv3Node(node_id='234', cloud_server_id='abc', description=rcv3_desc)] self.assertEqual( converge( DesiredGroupState(server_config={}, capacity=1), set([server('abc', ServerState.ACTIVE, servicenet_address='1.1.1.1', desired_lbs=s(clb_desc, rcv3_desc))]), set(current), 0), pbag([ ChangeCLBNode(lb_id='5', node_id='123', weight=1, condition=CLBNodeCondition.ENABLED, type=CLBNodeType.PRIMARY)]))
def _build(thing, on_route=pyrsistent.s()): if thing in on_route: raise ValueError("circular dependency detected", thing, on_route) if thing in ret: return ret[thing] on_route = on_route.add(thing) plugin = collection[thing] func = plugin.original dependencies, possible_dependencies, regular = plugin.extra my_dependencies, my_possible_dependencies = {}, {} for other_thing in dependencies: my_dependencies[other_thing] = _build(other_thing, on_route) for other_thing in possible_dependencies: builder = functools.partial(_build, other_thing, on_route) my_possible_dependencies[other_thing] = builder if regular: args = { 'build_' + key: value for key, value in my_possible_dependencies.items() } args.update(my_dependencies) ret[thing] = func(**args) else: ret[thing] = func(my_dependencies, my_possible_dependencies) return ret[thing]
def test_draining_server_has_all_enabled_lb_set_to_draining(self): """ If a draining server is associated with any load balancers, those load balancer nodes will be set to draining and the server is not deleted. The metadata on the server is not re-set to draining. This can happen for instance if the server was supposed to be deleted in a previous convergence run, and the server metadata was set but the load balancers update failed. Or if the server is set to be manually deleted via the API. """ self.assertEqual( converge( DesiredGroupState(server_config={}, capacity=0, draining_timeout=10.0), set([server('abc', state=ServerState.ACTIVE, metadata=dict([DRAINING_METADATA]), servicenet_address='1.1.1.1', desired_lbs=s(self.clb_desc, self.rcv3_desc))]), set([CLBNode(node_id='1', address='1.1.1.1', description=self.clb_desc)]), 1), pbag([ ChangeCLBNode(lb_id='1', node_id='1', weight=1, condition=CLBNodeCondition.DRAINING, type=CLBNodeType.PRIMARY) ]))
def test_active_server_is_drained_even_if_all_already_in_draining(self): """ If an active server is attached to load balancers, and all those load balancer nodes are already in draining but it cannot be removed yet, the server is set to draining state even though no load balancer actions need to be performed. This can happen for instance if the server was supposed to be deleted in a previous convergence run, and the load balancers were set to draining but setting the server metadata failed. """ self.assertEqual( converge( DesiredGroupState(server_config={}, capacity=0, draining_timeout=10.0), set([server('abc', state=ServerState.ACTIVE, servicenet_address='1.1.1.1', desired_lbs=s(self.clb_desc, self.rcv3_desc))]), set([CLBNode(node_id='1', address='1.1.1.1', description=copy_clb_desc( self.clb_desc, condition=CLBNodeCondition.DRAINING), connections=1, drained_at=0.0)]), 1), pbag([ SetMetadataItemOnServer(server_id='abc', key=DRAINING_METADATA[0], value=DRAINING_METADATA[1]), self.clstep ]))
def test_optimize_clb_removes(self): """ Aggregation is done on a per-load-balancer basis when remove nodes from a CLB. """ steps = pbag([ RemoveNodesFromCLB(lb_id='5', node_ids=s('1')), RemoveNodesFromCLB(lb_id='5', node_ids=s('2')), RemoveNodesFromCLB(lb_id='5', node_ids=s('3')), RemoveNodesFromCLB(lb_id='5', node_ids=s('4'))]) self.assertEqual( optimize_steps(steps), pbag([ RemoveNodesFromCLB(lb_id='5', node_ids=s('1', '2', '3', '4')) ]))
def test_multiple_lb_pending(self): """ When a server needs to be added to multiple LBs, it's only counted once. """ lb_nodes = [ CLBNode(node_id='1', description=CLBDescription(lb_id='foo', port=1), address='1.1.1.1'), CLBNode(node_id='2', description=CLBDescription(lb_id='foo', port=2), address='1.1.1.1'), CLBNode(node_id='3', description=CLBDescription(lb_id='bar', port=3), address='1.1.1.1'), CLBNode(node_id='4', description=CLBDescription(lb_id='bar', port=4), address='1.1.1.1'), ] desired_lbs = s(CLBDescription(lb_id='foo', port=1), CLBDescription(lb_id='foo', port=2), CLBDescription(lb_id='bar', port=3), CLBDescription(lb_id='bar', port=4)) self.assertEqual( is_autoscale_active( server('id1', ServerState.ACTIVE, servicenet_address='1.1.1.1', desired_lbs=desired_lbs), lb_nodes), True)
def test_mixed_optimization(self): """ Mixes of optimizable and unoptimizable steps still get optimized correctly. """ steps = pbag([ # CLB adds AddNodesToCLB( lb_id='5', address_configs=s(('1.1.1.1', CLBDescription(lb_id='5', port=80)))), AddNodesToCLB( lb_id='5', address_configs=s(('1.1.1.2', CLBDescription(lb_id='5', port=80)))), AddNodesToCLB( lb_id='6', address_configs=s(('1.1.1.1', CLBDescription(lb_id='6', port=80)))), AddNodesToCLB( lb_id='6', address_configs=s(('1.1.1.2', CLBDescription(lb_id='6', port=80)))), RemoveNodesFromCLB(lb_id='7', node_ids=s('1')), RemoveNodesFromCLB(lb_id='7', node_ids=s('2')), # Unoptimizable steps CreateServer(server_config=pmap({})), ]) self.assertEqual( optimize_steps(steps), pbag([ # Optimized CLB adds AddNodesToCLB( lb_id='5', address_configs=s(('1.1.1.1', CLBDescription(lb_id='5', port=80)), ('1.1.1.2', CLBDescription(lb_id='5', port=80)))), AddNodesToCLB( lb_id='6', address_configs=s(('1.1.1.1', CLBDescription(lb_id='6', port=80)), ('1.1.1.2', CLBDescription(lb_id='6', port=80)))), RemoveNodesFromCLB(lb_id='7', node_ids=s('1', '2')), # Unoptimizable steps CreateServer(server_config=pmap({})) ]))
def test_optimize_clb_removes(self): """ Aggregation is done on a per-load-balancer basis when remove nodes from a CLB. """ steps = pbag([ RemoveNodesFromCLB(lb_id='5', node_ids=s('1')), RemoveNodesFromCLB(lb_id='5', node_ids=s('2')), RemoveNodesFromCLB(lb_id='5', node_ids=s('3')), RemoveNodesFromCLB(lb_id='5', node_ids=s('4')) ]) self.assertEqual( optimize_steps(steps), pbag([ RemoveNodesFromCLB(lb_id='5', node_ids=s('1', '2', '3', '4')) ]))
def test_optimize_leaves_other_steps(self): """ Unoptimizable steps pass the optimizer unchanged. """ steps = pbag([ AddNodesToCLB(lb_id='5', address_configs=s( ('1.1.1.1', CLBDescription(lb_id='5', port=80)))), RemoveNodesFromCLB(lb_id='6', node_ids=s('1')), CreateServer(server_config=pmap({})), BulkRemoveFromRCv3(lb_node_pairs=pset([("lb-1", "node-a")])), BulkAddToRCv3(lb_node_pairs=pset([("lb-2", "node-b")])) # Note that the add & remove pair should not be the same; # the optimizer might reasonably optimize opposite # operations away in the future. ]) self.assertEqual(optimize_steps(steps), steps)
def test_mixed_optimization(self): """ Mixes of optimizable and unoptimizable steps still get optimized correctly. """ steps = pbag([ # CLB adds AddNodesToCLB(lb_id='5', address_configs=s( ('1.1.1.1', CLBDescription(lb_id='5', port=80)))), AddNodesToCLB(lb_id='5', address_configs=s( ('1.1.1.2', CLBDescription(lb_id='5', port=80)))), AddNodesToCLB(lb_id='6', address_configs=s( ('1.1.1.1', CLBDescription(lb_id='6', port=80)))), AddNodesToCLB(lb_id='6', address_configs=s( ('1.1.1.2', CLBDescription(lb_id='6', port=80)))), RemoveNodesFromCLB(lb_id='7', node_ids=s('1')), RemoveNodesFromCLB(lb_id='7', node_ids=s('2')), # Unoptimizable steps CreateServer(server_config=pmap({})), ]) self.assertEqual( optimize_steps(steps), pbag([ # Optimized CLB adds AddNodesToCLB( lb_id='5', address_configs=s( ('1.1.1.1', CLBDescription(lb_id='5', port=80)), ('1.1.1.2', CLBDescription(lb_id='5', port=80)))), AddNodesToCLB( lb_id='6', address_configs=s( ('1.1.1.1', CLBDescription(lb_id='6', port=80)), ('1.1.1.2', CLBDescription(lb_id='6', port=80)))), RemoveNodesFromCLB(lb_id='7', node_ids=s('1', '2')), # Unoptimizable steps CreateServer(server_config=pmap({})) ]))
def test_identify_with_non_alphanumeric_tag_status_uid(): uid = 'UID %-' tag = 'a tag #0' status = 'a status #0' m0 = messages.BusMessage(tag=tag, status=status, payload=0, seeds=m()) m1 = m0.identify(uid) seeds_c = freeze({tag: s(uid)}) mc = messages.BusMessage(tag=tag, status=status, payload=0, seeds=seeds_c) assert (m1 == mc)
def add_edges(point_map): """Simple edge creation that adds edges only between a point and its nearest neighbor""" edges = [] for anchor in point_map.keys(): distances = [(search, distance(point_map[anchor], point_map[search])) for search in set(point_map.keys()).difference({anchor})] min_distance = min(distances, key=lambda y: y[1]) edges.append(s(anchor, min_distance[0])) return pset(edges)
def test_optimize_leaves_other_steps(self): """ Unoptimizable steps pass the optimizer unchanged. """ steps = pbag([ AddNodesToCLB( lb_id='5', address_configs=s(('1.1.1.1', CLBDescription(lb_id='5', port=80)))), RemoveNodesFromCLB(lb_id='5', node_ids=s('1')), CreateServer(server_config=pmap({})), BulkRemoveFromRCv3(lb_node_pairs=pset([("lb-1", "node-a")])), BulkAddToRCv3(lb_node_pairs=pset([("lb-2", "node-b")])) # Note that the add & remove pair should not be the same; # the optimizer might reasonably optimize opposite # operations away in the future. ]) self.assertEqual( optimize_steps(steps), steps)
def test_all_changes(self): """ Remove, change, and add a node to a load balancer all together """ descs = [CLBDescription(lb_id='5', port=80), CLBDescription(lb_id='6', port=80, weight=2), RCv3Description(lb_id='c6fe49fa-114a-4ea4-9425-0af8b30ff1e7')] current = [ CLBNode(node_id='123', address='1.1.1.1', description=CLBDescription(lb_id='5', port=8080)), CLBNode(node_id='234', address='1.1.1.1', description=copy_clb_desc(descs[1], weight=1)), RCv3Node(node_id='345', cloud_server_id='abc', description=RCv3Description( lb_id='e762e42a-8a4e-4ffb-be17-f9dc672729b2')) ] self.assertEqual( converge( DesiredGroupState(server_config={}, capacity=1), set([server('abc', ServerState.ACTIVE, servicenet_address='1.1.1.1', desired_lbs=pset(descs))]), set(current), 0), pbag([ AddNodesToCLB( lb_id='5', address_configs=s(('1.1.1.1', CLBDescription(lb_id='5', port=80)))), ChangeCLBNode(lb_id='6', node_id='234', weight=2, condition=CLBNodeCondition.ENABLED, type=CLBNodeType.PRIMARY), RemoveNodesFromCLB(lb_id='5', node_ids=s('123')), BulkAddToRCv3(lb_node_pairs=s( ('c6fe49fa-114a-4ea4-9425-0af8b30ff1e7', 'abc'))), BulkRemoveFromRCv3(lb_node_pairs=s( ('e762e42a-8a4e-4ffb-be17-f9dc672729b2', 'abc'))) ]))
def test_draining_server_waiting_for_timeout_some_lbs_removed(self): """ Load balancers that can be removed are removed, even if the server is already in draining state is waiting for the draining timeout on some load balancers. """ other_clb_desc = CLBDescription(lb_id='9', port=80) self.assertEqual( converge( DesiredGroupState(server_config={}, capacity=0, draining_timeout=2.0), set([server('abc', state=ServerState.ACTIVE, metadata=dict([DRAINING_METADATA]), servicenet_address='1.1.1.1', desired_lbs=s(self.clb_desc, self.rcv3_desc, other_clb_desc))]), set([ # This node is in draining - nothing will be done to it CLBNode(node_id='1', address='1.1.1.1', description=copy_clb_desc( self.clb_desc, condition=CLBNodeCondition.DRAINING), drained_at=1.0, connections=1), # This node is done draining, it can be removed CLBNode(node_id='2', address='1.1.1.1', description=copy_clb_desc( other_clb_desc, condition=CLBNodeCondition.DRAINING), drained_at=0.0), # This node is not drainable, it can be removed RCv3Node(node_id='3', cloud_server_id='abc', description=self.rcv3_desc)]), 2), pbag([ RemoveNodesFromCLB(lb_id='9', node_ids=s('2')), BulkRemoveFromRCv3(lb_node_pairs=s( (self.rcv3_desc.lb_id, 'abc'))), self.clstep ]))
def perimeter_positions(self, game: Game): all_positions_set = pset( game.black_positions.union(game.white_positions)) all_positions = plist(all_positions_set) horizon = s() while len(all_positions) > 0: head = all_positions.first all_positions = all_positions.rest neighbors = self.get_neighbors(head) horizon = horizon.union(neighbors) return horizon.difference(all_positions_set)
def initial_game(self) -> Game: lower = int(self.board_size / 2) - 1 upper = int(self.board_size / 2) black_positions = s( Position(x_position=lower, y_position=lower, board_size=self.board_size), Position(x_position=upper, y_position=upper, board_size=self.board_size)) white_positions = s( Position(x_position=lower, y_position=upper, board_size=self.board_size), Position(x_position=upper, y_position=lower, board_size=self.board_size)) return Game(black_positions=black_positions, white_positions=white_positions)
def test_active_server_can_be_deleted_if_all_lbs_can_be_removed(self): """ If an active server to be scaled down can be removed from all the load balancers, the server can be deleted. It is not first put into draining state. """ self.assertEqual( converge( DesiredGroupState(server_config={}, capacity=0), set([server('abc', state=ServerState.ACTIVE, servicenet_address='1.1.1.1', desired_lbs=s(self.clb_desc, self.rcv3_desc))]), set([CLBNode(node_id='1', address='1.1.1.1', description=self.clb_desc), RCv3Node(node_id='2', cloud_server_id='abc', description=self.rcv3_desc)]), 0), pbag([ DeleteServer(server_id='abc'), RemoveNodesFromCLB(lb_id='1', node_ids=s('1')), BulkRemoveFromRCv3(lb_node_pairs=s( (self.rcv3_desc.lb_id, 'abc'))) ]))
def test_optimize_clb_adds(self): """ Multiple :class:`AddNodesToCLB` steps for the same LB are merged into one. """ steps = pbag([ AddNodesToCLB( lb_id='5', address_configs=s(('1.1.1.1', CLBDescription(lb_id='5', port=80)))), AddNodesToCLB( lb_id='5', address_configs=s(('1.2.3.4', CLBDescription(lb_id='5', port=80))))]) self.assertEqual( optimize_steps(steps), pbag([ AddNodesToCLB( lb_id='5', address_configs=s( ('1.1.1.1', CLBDescription(lb_id='5', port=80)), ('1.2.3.4', CLBDescription(lb_id='5', port=80))) )]))
def test_optimize_clb_adds(self): """ Multiple :class:`AddNodesToCLB` steps for the same LB are merged into one. """ steps = pbag([ AddNodesToCLB(lb_id='5', address_configs=s( ('1.1.1.1', CLBDescription(lb_id='5', port=80)))), AddNodesToCLB(lb_id='5', address_configs=s( ('1.2.3.4', CLBDescription(lb_id='5', port=80)))) ]) self.assertEqual( optimize_steps(steps), pbag([ AddNodesToCLB( lb_id='5', address_configs=s( ('1.1.1.1', CLBDescription(lb_id='5', port=80)), ('1.2.3.4', CLBDescription(lb_id='5', port=80)))) ]))
def test_building_servers_are_deleted(self): """ A building server to be scaled down is just deleted and removed from any load balancers. It is not put into a draining state, nor are the load balancers nodes drained, even if the timeout is greater than zero. """ self.assertEqual( converge( DesiredGroupState(server_config={}, capacity=0, draining_timeout=10.0), set([server('abc', state=ServerState.BUILD, servicenet_address='1.1.1.1', desired_lbs=s(self.clb_desc, self.rcv3_desc))]), set([CLBNode(node_id='1', address='1.1.1.1', description=self.clb_desc), RCv3Node(node_id='2', cloud_server_id='abc', description=self.rcv3_desc)]), 0), pbag([ DeleteServer(server_id='abc'), RemoveNodesFromCLB(lb_id='1', node_ids=s('1')), BulkRemoveFromRCv3(lb_node_pairs=s( (self.rcv3_desc.lb_id, 'abc'))) ]))
def test_active_server_without_load_balancers_can_be_deleted(self): """ If an active server to be scaled down is not attached to any load balancers, even if it should be, it can be deleted. It is not first put into draining state. """ self.assertEqual( converge( DesiredGroupState(server_config={}, capacity=0, draining_timeout=10.0), set([server('abc', state=ServerState.ACTIVE, desired_lbs=s(self.clb_desc, self.rcv3_desc))]), set(), 0), pbag([DeleteServer(server_id='abc')]))
def test_children(self): fs = self.FS() tempdir = fs.temporary_directory() self.addCleanup(fs.remove, tempdir) a = tempdir.descendant("a") b = tempdir.descendant("b") c = tempdir.descendant("b", "c") d = tempdir.descendant("d") fs.touch(path=a) fs.create_directory(path=b) fs.touch(path=c) fs.link(source=c, to=d) self.assertEqual(fs.children(path=tempdir), s(a, b, d))
def test_remove_does_not_follow_directory_links(self): fs = self.FS() tempdir = fs.temporary_directory() self.addCleanup(fs.remove, tempdir) directory = tempdir.descendant("directory") fs.create_directory(path=directory) fs.touch(directory.descendant("a")) link = tempdir.descendant("link") fs.link(source=directory, to=link) self.assertTrue(fs.is_link(path=link)) fs.remove(path=link) self.assertEqual( fs.children(path=directory), s(directory.descendant("a")), )
def reflexiveTransitiveClosure(self): closure = self.relation for i in self.set: closure = closure.add((i, i)) while True: new_relation = s() for i in closure: for j in closure: if i[1] == j[0]: new_relation = new_relation.add((i[0], j[1])) current_closure = closure | new_relation if closure == current_closure: break closure = current_closure return Relation(self.set, closure)
def reflexive_transitive(self): """reflexive-transitive closure""" relation = self.relation temp = s() for x in self.members: if (x, x) not in self.relation: temp = temp.add((x, x)) while True: for x, y in relation: for w, v in relation: if w == y: temp = temp.add((x, v)) current = relation.union(temp) if current == relation: break relation = current return get_relation_class(self.members, relation)
def no_interesctions(point_map): """Finds all of the graph edges such that all nodes are connected and no edges 'intersect' on the 2d plane""" all_edges = pset([ s(anchor, search) for anchor in point_map.keys() for search in point_map.keys() if anchor != search ]) edges_by_distance = sorted(plist(all_edges), key=lambda y: edge_distance(y, point_map)) edges = [] for edge in edges_by_distance: pair_a = edge_to_pair(edge, point_map) if not any([ find_affine_intersection(pair_a, edge_to_pair(y, point_map)) for y in edges ]): edges.append(edge) return edges
def test_remove(self): fs = self.FS() tempdir = fs.temporary_directory() self.addCleanup(fs.remove, tempdir) directory = tempdir.descendant("directory") fs.create_directory(directory) a = directory.descendant("a") b = directory.descendant("b") c = directory.descendant("b", "c") d = directory.descendant("d") fs.touch(path=a) fs.create_directory(path=b) fs.touch(path=c) fs.touch(path=d) fs.remove(directory) self.assertEqual(fs.children(path=tempdir), s())
def test_glob_children(self): fs = self.FS() tempdir = fs.temporary_directory() self.addCleanup(fs.remove, tempdir) a = tempdir.descendant("a") b = tempdir.descendant("b") c = tempdir.descendant("b", "c") abc = tempdir.descendant("abc") fedcba = tempdir.descendant("fedcba") fs.touch(path=a) fs.create_directory(path=b) fs.touch(path=c) fs.touch(path=abc) fs.touch(path=fedcba) self.assertEqual( fs.glob_children(path=tempdir, glob="*b*"), s(b, abc, fedcba), )
def test_clb_remove_multiple_load_balancers(self): """ Multiple :class:`RemoveNodesFromCLB` steps for the same LB are merged into one. """ steps = pbag([ RemoveNodesFromCLB(lb_id='5', node_ids=s('1')), RemoveNodesFromCLB(lb_id='5', node_ids=s('2')), RemoveNodesFromCLB(lb_id='6', node_ids=s('3')), RemoveNodesFromCLB(lb_id='6', node_ids=s('4')) ]) self.assertEqual( optimize_steps(steps), pbag([ RemoveNodesFromCLB(lb_id='5', node_ids=s('1', '2')), RemoveNodesFromCLB(lb_id='6', node_ids=s('3', '4')) ]))
def __init__(self, game: Game) -> None: root = tk.Tk() root.resizable(False, False) root.title(TITLE) self.canvas = tk.Canvas( root, height=SCREEN_SIZE, width=SCREEN_SIZE, bg=COLOR_BG, highlightthickness=0, ) self.game = game self.text = Text(root, game) for player in s(Player.BLUE, Player.RED): self.generate_base_polygons(game.board, player) for c in game.board.cycles: CyclePolygon(self, game, c) self.canvas.pack(side="left", fill="both") root.mainloop()