def validate_ip_blocks(ips_list_1, ips_list_2): ip_block_1 = IpBlock() ip_block_2 = IpBlock() for ip in ips_list_1: ip_block_1 |= ip for ip in ips_list_2: ip_block_2 |= ip return ip_block_1.contained_in(ip_block_2)
def test_eq(self): default_namespace = K8sNamespace('default') pod_a = Pod('A', default_namespace) ip1 = IpBlock("1.2.3.0/24") ip2 = IpBlock("1.2.3.0/32") ip3 = ip1 - ip2 set1 = PeerSet({pod_a, ip1}) set2 = PeerSet({pod_a, ip2, ip3}) self.assertTrue(set1 == set2)
def test_subtract(self): self.assertTrue(True) default_namespace = K8sNamespace('default') pod_a = Pod('A', default_namespace) ip1 = IpBlock("1.2.3.0/24") ip2 = IpBlock("1.2.3.0/32") ip3 = ip1 - ip2 set1 = PeerSet({pod_a, ip1}) set2 = PeerSet({pod_a, ip2}) set3 = PeerSet({ip3}) self.assertTrue(set1-set2 == set3)
def _get_rule_peers(self, entity_rule): """ Parse the peer-specifying parts of the source/destination parts of a rule :param dict entity_rule: The object to parse :return: The peers that are specified by nets/notNets/selector/notSelector/namespaceSelector :rtype: PeerSet """ nets = entity_rule.get('nets') if nets: rule_ips = IpBlock(nets[0]) for cidr in nets[1:]: rule_ips |= IpBlock(cidr) else: rule_ips = IpBlock.get_all_ips_block() not_nets = entity_rule.get('notNets', []) for cidr in not_nets: rule_ips -= IpBlock(cidr) ns_selector = self._get_value_as_str(entity_rule, 'namespaceSelector') pod_selector = self._get_value_as_str(entity_rule, 'selector') not_pod_selector = self._get_value_as_str(entity_rule, 'notSelector') if ns_selector: rule_peers = self._parse_label_selector(ns_selector, entity_rule, namespace_selector=True) elif pod_selector: rule_peers = self.peer_container.get_namespace_pods(self.namespace) elif nets or not_nets: rule_peers = PeerSet() rule_peers.add(rule_ips) else: rule_peers = self.peer_container.get_all_peers_group(True) ns_to_use = self.namespace if not ns_selector else None if pod_selector is not None: selected_pods = self._parse_label_selector(pod_selector, entity_rule, ns_to_use) if pod_selector.strip() != 'all()' and selected_pods == rule_peers: self.warning( 'selector has no effect - better delete or use "all()"', entity_rule) rule_peers &= selected_pods if not_pod_selector: rule_peers -= self._parse_label_selector(not_pod_selector, entity_rule, ns_to_use) if (nets or not_nets) and (ns_selector or pod_selector): rule_peers = PeerSet() self.warning( 'Mixing ip-based selection with label-based selection is likely a mistake', entity_rule) return rule_peers
def test_or(self): default_namespace = K8sNamespace('default') pod_a = Pod('A', default_namespace) pod_b = Pod('B', default_namespace) ip1 = IpBlock("1.2.3.0/24") ip2 = IpBlock("1.2.3.0/32") ip3 = ip1 - ip2 set1 = PeerSet({pod_a, pod_b, ip1}) set2 = PeerSet({pod_a, ip2}) set3 = PeerSet({pod_b, ip3}) self.assertTrue(set2 | set3 == set1) set2 |= set3 self.assertTrue(set2 == set1)
def test_and(self): default_namespace = K8sNamespace('default') pod_a = Pod('A', default_namespace) pod_b = Pod('B', default_namespace) ip1 = IpBlock("1.2.3.0/24") ip2 = IpBlock("1.2.3.0/32") pod_set_1 = {pod_a, pod_b, ip2} pod_set_2 = {pod_a, ip1} a = PeerSet(pod_set_1) b = PeerSet(pod_set_2) res1 = a & b self.assertTrue(res1 == PeerSet({pod_a, ip2})) a &= b self.assertTrue(a == res1)
def parse_ip_block(ips_list, not_ips_list): """ parse ipBlocks elements (within a source component of a rule) :param list[str] ips_list: list of ip-block addresses (either ip address or ip-block cidr) :param list[str] not_ips_list: negative list of ip-block addresses (either ip address or ip-block cidr) :return: A PeerSet containing the relevant IpBlocks :rtype: Peer.PeerSet """ ips_list = ['0.0.0.0/0', '::/0'] if ips_list is None else ips_list # If not set, any IP is allowed not_ips_list = [] if not_ips_list is None else not_ips_list res_ip_block = IpBlock() for cidr in ips_list: res_ip_block |= IpBlock(cidr) for cidr in not_ips_list: res_ip_block -= IpBlock(cidr) return res_ip_block.split()
def _add_networkset_from_yaml(self, networkset_object): """ Add a Calico NetworkSet to the container based on the given resource instance :param dict networkset_object: The networkSet object to add :return: None """ kind = networkset_object.get('kind') is_global = kind == 'GlobalNetworkSet' metadata = networkset_object.get('metadata', {}) spec = networkset_object.get('spec', {}) name = metadata.get('name', '') if name == '': print('NetworkSet must have a name', file=stderr) return if is_global: namespace = None else: namespace_name = metadata.get('namespace', 'default') namespace = self.get_namespace(namespace_name) ipb = IpBlock(name=name, namespace=namespace, is_global=is_global) labels = metadata.get('labels', {}) if not labels: print(f'NetworkSet {name} should have labels', file=stderr) for key, val in labels.items(): ipb.set_label(key, val) cidrs = spec.get('nets', {}) for cidr in cidrs: ipb.add_cidr(cidr) self._add_peer(ipb)
def get_all_peers_group(self, add_external_ips=False, include_globals=True): """ Return all peers known in the system :param bool add_external_ips: Whether to also add the full range of ips :param bool include_globals: Whether to include global peers :return PeerSet: The required set of peers """ res = PeerSet() for peer in self.peer_set: if include_globals or not peer.is_global_peer(): res.add(peer) if add_external_ips: res.add(IpBlock.get_all_ips_block()) return res
def _make_deny_rules(self, allowed_conns): """ Make deny rules from the given connections :param TcpLikeProperties allowed_conns: the given allowed connections :return: the list of deny IngressPolicyRules """ all_peers_and_ip_blocks = self.peer_container.peer_set.copy() all_peers_and_ip_blocks.add( IpBlock.get_all_ips_block()) # add IpBlock of all IPs all_conns = self._make_tcp_like_properties(PortSet(True), all_peers_and_ip_blocks) denied_conns = all_conns - allowed_conns res = self._make_rules_from_conns(denied_conns) # Add deny rule for all protocols but TCP , relevant for all peers and ip blocks non_tcp_conns = ConnectionSet.get_non_tcp_connections() res.append(IngressPolicyRule(all_peers_and_ip_blocks, non_tcp_conns)) return res
def test_get_peer_set(self): ip1 = IpBlock("1.2.3.0/24") ip1_set = PeerSet({ip1}) self.assertTrue(ip1_set == ip1.get_peer_set()) self.assertTrue(PeerSet() == (ip1-ip1).get_peer_set())
def _make_tcp_like_properties(self, dest_ports, peers, paths_dfa=None, hosts_dfa=None): """ get TcpLikeProperties with TCP allowed connections, corresponding to input properties cube. TcpLikeProperties should not contain named ports: substitute them with corresponding port numbers, per peer :param PortSet dest_ports: ports set for dest_ports dimension (possibly containing named ports) :param PeerSet peers: the set of (target) peers :param MinDFA paths_dfa: MinDFA obj for paths dimension :param MinDFA hosts_dfa: MinDFA obj for hosts dimension :return: TcpLikeProperties with TCP allowed connections, corresponding to input properties cube """ assert peers base_peer_set = self.peer_container.peer_set.copy() base_peer_set.add(IpBlock.get_all_ips_block()) if not dest_ports.named_ports: peers_interval = base_peer_set.get_peer_interval_of(peers) return TcpLikeProperties(source_ports=PortSet(True), dest_ports=dest_ports, methods=MethodSet(True), paths=paths_dfa, hosts=hosts_dfa, peers=peers_interval, base_peer_set=base_peer_set) assert not dest_ports.port_set assert len(dest_ports.named_ports) == 1 port = list(dest_ports.named_ports)[0] tcp_properties = None for peer in peers: named_ports = peer.get_named_ports() real_port = named_ports.get(port) if not real_port: self.warning( f'Missing named port {port} in the pod {peer}. Ignoring the pod' ) continue if real_port[1] != 'TCP': self.warning( f'Illegal protocol {real_port[1]} in the named port {port} ingress target pod {peer}.' f'Ignoring the pod') continue peer_in_set = PeerSet() peer_in_set.add(peer) ports = PortSet() ports.add_port(real_port[0]) props = TcpLikeProperties( source_ports=PortSet(True), dest_ports=ports, methods=MethodSet(True), paths=paths_dfa, hosts=hosts_dfa, peers=base_peer_set.get_peer_interval_of(peer_in_set), base_peer_set=base_peer_set) if tcp_properties: tcp_properties |= props else: tcp_properties = props return tcp_properties