def assign_ips(cls, nodes_ids, network_name): """Idempotent assignment IP addresses to nodes. All nodes passed as first argument get IP address from network, referred by network_name. If node already has IP address from this network, it remains unchanged. If one of the nodes is the node from other cluster, this func will fail. :param node_ids: List of nodes IDs in database. :type node_ids: list :param network_name: Network name :type network_name: str :returns: None :raises: Exception, errors.AssignIPError """ cluster_id = db().query(Node).get(nodes_ids[0]).cluster_id for node_id in nodes_ids: node = db().query(Node).get(node_id) if node.cluster_id != cluster_id: raise Exception( u"Node id='{0}' doesn't belong to cluster_id='{1}'".format( node_id, cluster_id)) network = db().query(NetworkGroup).\ filter(NetworkGroup.cluster_id == cluster_id).\ filter_by(name=network_name).first() if not network: raise errors.AssignIPError( u"Network '%s' for cluster_id=%s not found." % (network_name, cluster_id)) for node_id in nodes_ids: node_ips = imap( lambda i: i.ip_addr, cls._get_ips_except_admin(node_id=node_id, network_id=network.id)) # check if any of node_ips in required ranges ip_already_assigned = False for ip in node_ips: if cls.check_ip_belongs_to_net(ip, network): logger.info(u"Node id='{0}' already has an IP address " "inside '{1}' network.".format( node_id, network.name)) ip_already_assigned = True break if ip_already_assigned: continue # IP address has not been assigned, let's do it logger.info("Assigning IP for node '{0}' in network '{1}'".format( node_id, network_name)) free_ip = cls.get_free_ips(network.id)[0] ip_db = IPAddr(network=network.id, node=node_id, ip_addr=free_ip) db().add(ip_db) db().commit()
def assign_admin_ips(cls, nodes): """Method for assigning admin IP addresses to nodes. :param node_id: Node database ID. :type node_id: int :param num: Number of IP addresses for node. :type num: int :returns: None """ # Check which nodes need ips # verification that node.ip (which is reported by agent) belongs # to one of the ranges of required to be able to reuse admin ip address # also such approach is backward compatible nodes_need_ips = defaultdict(list) for node in nodes: node_id = node.id admin_net = cls.get_admin_network_group(node_id) node_admin_ips = db().query(IPAddr).filter_by(node=node_id, network=admin_net.id) logger.debug(u"Trying to assign admin ip: node=%s", node_id) if not db().query(node_admin_ips.exists()).scalar(): reusable_ip = cls.reusable_ip_address(node, admin_net) if reusable_ip: db().add(reusable_ip) else: nodes_need_ips[admin_net].append(node_id) db().flush() for admin_net, nodes in six.iteritems(nodes_need_ips): free_ips = cls.get_free_ips(admin_net, len(nodes)) for ip, n in zip(free_ips, nodes): ip_db = IPAddr(node=n, ip_addr=ip, network=admin_net.id) db().add(ip_db) db().flush()
def assign_admin_ips(cls, node_id, num=1): """Method for assigning admin IP addresses to nodes. :param node_id: Node database ID. :type node_id: int :param num: Number of IP addresses for node. :type num: int :returns: None """ admin_net_id = cls.get_admin_network_group_id() node_admin_ips = db().query(IPAddr).filter_by( node=node_id, network=admin_net_id ).all() if not node_admin_ips or len(node_admin_ips) < num: admin_net = db().query(NetworkGroup).get(admin_net_id) logger.debug( u"Trying to assign admin ips: node=%s count=%s", node_id, num - len(node_admin_ips) ) free_ips = cls.get_free_ips( admin_net.id, num=num - len(node_admin_ips) ) logger.info(len(free_ips)) for ip in free_ips: ip_db = IPAddr( node=node_id, ip_addr=ip, network=admin_net_id ) db().add(ip_db) db().commit()
def test_fail_on_no_vip_metadata(self): not_vip_ip_addr = IPAddr(network=self.cluster.network_groups[0].id, ip_addr="127.0.0.1", vip_name=None) self.db.add(not_vip_ip_addr) self.db.flush() not_vip_id = not_vip_ip_addr.get('id') resp = self.app.get(reverse(self.handler_name, kwargs={ 'cluster_id': self.cluster['id'], 'ip_addr_id': not_vip_id }), headers=self.default_headers, expect_errors=True) self.assertEqual(400, resp.status_code) self.assertIn("has no VIP metadata attached", resp.json_body['message'])
def reusable_ip_address(cls, node, network): """Verifies that ip belongs to network and creates IPAddr in case it is :param node: Node database object. :param network: Network database object. :returns: IPAddr object or None """ if node.ip and cls.check_ip_belongs_to_net(node.ip, network): return IPAddr(node=node.id, ip_addr=node.ip, network=network.id) return None
def assign_vip(cls, cluster_id, network_name): """Idempotent assignment VirtualIP addresses to cluster. Returns VIP for given cluster and network. It's required for HA deployment to have IP address not assigned to any of nodes. Currently we need one VIP per network in cluster. If cluster already has IP address from this network, it remains unchanged. If one of the nodes is the node from other cluster, this func will fail. :param cluster_id: Cluster database ID. :type cluster_id: int :param network_name: Network name :type network_name: str :returns: None :raises: Exception """ cluster = objects.Cluster.get_by_uid(cluster_id) if not cluster: raise Exception(u"Cluster id='%s' not found" % cluster_id) network = db().query(NetworkGroup).\ filter(NetworkGroup.cluster_id == cluster_id).\ filter_by(name=network_name).first() if not network: raise Exception(u"Network '%s' for cluster_id=%s not found." % (network_name, cluster_id)) admin_net_id = cls.get_admin_network_group_id() cluster_ips = [ne.ip_addr for ne in db().query(IPAddr).filter_by( network=network.id, node=None ).filter( not_(IPAddr.network == admin_net_id) ).all()] # check if any of used_ips in required cidr: network.cidr ips_belongs_to_net = False for ip in cluster_ips: if cls.check_ip_belongs_to_net(ip, network): ips_belongs_to_net = True break if ips_belongs_to_net: vip = cluster_ips[0] else: # IP address has not been assigned, let's do it vip = cls.get_free_ips(network.id)[0] ne_db = IPAddr(network=network.id, ip_addr=vip) db().add(ne_db) db().commit() return vip
def reusable_ip_address(cls, node, network): """Verifies that ip belongs to network and creates IPAddr in case it did :param node: Node database object. :param network: Network database object. :returns: IPAddr object or None """ #此处暂时先注释掉 #if node.ip and cls.check_ip_belongs_to_net(node.ip, network): logger.info("the node {0} admin ip is {1} power ip is {2}".format( node.name, node.ip, node.power_ip)) return IPAddr(node=node.id, ip_addr=node.ip, network=network.id)
def test_fail_on_no_vip_metadata(self): not_vip_ip_addr = IPAddr( network=self.cluster.network_groups[0].id, ip_addr="127.0.0.1", vip_name=None ) self.db.add(not_vip_ip_addr) self.db.flush() not_vip_id = not_vip_ip_addr.get('id') resp = self.app.get( reverse( self.handler_name, kwargs={ 'cluster_id': self.cluster['id'], 'ip_addr_id': not_vip_id } ), headers=self.default_headers, expect_errors=True ) self.assertEqual(400, resp.status_code)
def _create_ip_addrs_by_rules(self, cluster, rules): created_ips = [] for net_group in cluster.network_groups: if net_group.name not in rules: continue vips_by_types = rules[net_group.name] for vip_type, ip_addr in vips_by_types.items(): ip = IPAddr( network=net_group.id, ip_addr=ip_addr, vip_type=vip_type, ) self.db.add(ip) created_ips.append(ip) if created_ips: self.db.flush() return created_ips
def assign_vip(cls, cluster, network_name, vip_type=consts.NETWORK_VIP_TYPES.haproxy): """Idempotent assignment of VirtualIP addresses to cluster. Returns VIP for given cluster and network. It's required for HA deployment to have IP address not assigned to any of nodes. Currently we need one VIP per network in cluster. If cluster already has IP address from this network, it remains unchanged. If one of the nodes is the node from other cluster, this func will fail. :param cluster: Cluster instance :type cluster: Cluster model :param network_name: Network name :type network_name: str :param vip_type: Type of VIP :type vip_type: str :returns: assigned VIP (string) :raises: Exception """ group_id = objects.Cluster.get_controllers_group_id(cluster) network = db().query(NetworkGroup).\ filter_by(name=network_name, group_id=group_id).first() if not network: raise Exception(u"Network '%s' for cluster_id=%s not found." % (network_name, cluster.id)) cluster_vip = db().query(IPAddr).filter_by(network=network.id, node=None, vip_type=vip_type).first() # check if cluster_vip is in required cidr: network.cidr if cluster_vip and cls.check_ip_belongs_to_net(cluster_vip.ip_addr, network): return cluster_vip.ip_addr # IP address has not been assigned, let's do it vip = cls.get_free_ips(network)[0] ne_db = IPAddr(network=network.id, ip_addr=vip, vip_type=vip_type) db().add(ne_db) db().flush() return vip
def test_get_free_ips_from_ranges(self): ranges = [IPRange("192.168.33.2", "192.168.33.222")] ips = self.env.network_manager.get_free_ips_from_ranges( 'management', ranges, set(), 3) self.assertItemsEqual(["192.168.33.2", "192.168.33.3", "192.168.33.4"], ips) self.db.add(IPAddr(ip_addr="192.168.33.3")) self.db.flush() ips = self.env.network_manager.get_free_ips_from_ranges( 'management', ranges, set(), 3) self.assertItemsEqual(["192.168.33.2", "192.168.33.4", "192.168.33.5"], ips) ips = self.env.network_manager.get_free_ips_from_ranges( 'management', ranges, set(["192.168.33.5", "192.168.33.8"]), 7) self.assertItemsEqual([ "192.168.33.2", "192.168.33.4", "192.168.33.6", "192.168.33.7", "192.168.33.9", "192.168.33.10", "192.168.33.11" ], ips)
def test_get_vip_fail_if_ip_from_generic_admin_net(self): generic_admin_id = next(net for net in self.net_manager.get_admin_networks( cluster_nodegroup_info=True) if net['node_group_id'] is None)['id'] ip_addr_db = IPAddr(ip_addr='127.0.0.1', network=generic_admin_id) self.db.add(ip_addr_db) self.db.flush() resp = self.app.get(reverse(self.handler_name, kwargs={ 'cluster_id': self.cluster['id'], 'ip_addr_id': ip_addr_db.id }), headers=self.default_headers, expect_errors=True) self.assertEqual(resp.status_code, 400) self.assertIn('belongs to default Admin network and cannot be a VIP', resp.json_body['message'])
def assign_ips(cls, nodes, network_name): """Idempotent assignment IP addresses to nodes. All nodes passed as first argument get IP address from network, referred by network_name. If node already has IP address from this network, it remains unchanged. If one of the nodes is the node from other cluster, this func will fail. :param node_ids: List of nodes IDs in database. :type node_ids: list :param network_name: Network name :type network_name: str :returns: None :raises: Exception, errors.AssignIPError """ cluster_id = nodes[0].cluster_id for node in nodes: if node.cluster_id != cluster_id: raise Exception( u"Node id='{0}' doesn't belong to cluster_id='{1}'".format( node.id, cluster_id)) network_groups = db().query(NetworkGroup).\ filter_by(name=network_name) if not network_groups: raise errors.AssignIPError( u"Network '%s' for cluster_id=%s not found." % (network_name, cluster_id)) # Check which nodes need ips nodes_need_ips = defaultdict(list) for node in nodes: node_id = node.id if network_name == 'public' and \ not objects.Node.should_have_public(node): continue group_id = (node.group_id or objects.Cluster.get_default_group(node.cluster).id) network = network_groups.filter( or_( NetworkGroup.group_id == group_id, NetworkGroup.group_id == None # flake8: noqa )).first() node_ips = imap( lambda i: i.ip_addr, cls._get_ips_except_admin(node_id=node_id, network_id=network.id)) # check if any of node_ips in required ranges ip_already_assigned = False for ip in node_ips: if cls.check_ip_belongs_to_net(ip, network): logger.info(u"Node id='{0}' already has an IP address " "inside '{1}' network.".format( node_id, network.name)) ip_already_assigned = True break if ip_already_assigned: continue nodes_need_ips[network].append(node_id) # Get and assign ips for nodes for network, nodes in six.iteritems(nodes_need_ips): free_ips = cls.get_free_ips(network, len(nodes)) for ip, n in zip(free_ips, nodes): logger.info( "Assigning IP for node '{0}' in network '{1}'".format( n, network_name)) pxeip = cls.get_admin_ip_for_node(n) logger.info("pxeip is {0}".format(pxeip)) newip = cls.handleipgroup(pxeip, ip) logger.info("newip is {0}".format(newip)) ip_db = IPAddr(node=n, ip_addr=newip, network=network.id) db().add(ip_db) db().flush()