def neutron_check_segmentation_ids(self): """1. check networks VLAN IDs not in Neutron L2 private VLAN ID range for VLAN segmentation only 2. check networks VLAN IDs should not intersect (neutron) """ tagged_nets = dict((n["name"], n["vlan_start"]) for n in filter( lambda n: (n["vlan_start"] is not None), self.networks)) if tagged_nets: if self.task.cluster.network_config.segmentation_type == \ consts.NEUTRON_SEGMENT_TYPES.vlan: # check networks tags not in Neutron L2 private VLAN ID range vrange = self.network_config['vlan_range'] net_intersect = [name for name, vlan in tagged_nets.iteritems() if vrange[0] <= vlan <= vrange[1]] if net_intersect: nets_with_errors = ", ". \ join(net_intersect) err_msg = u"VLAN tags of {0} network(s) intersect with " \ u"VLAN ID range defined for Neutron L2. " \ u"Networks VLAN tags must not intersect " \ u"with Neutron L2 VLAN ID range.". \ format(nets_with_errors) raise errors.NetworkCheckError(err_msg) # check networks VLAN IDs should not intersect net_intersect = [name for name, vlan in tagged_nets.iteritems() if tagged_nets.values().count(vlan) >= 2] if net_intersect: err_msg = u"{0} networks use the same VLAN tags. " \ u"You should assign different VLAN tag " \ u"to every network.".format(", ".join(net_intersect)) raise errors.NetworkCheckError(err_msg)
def expose_network_check_error_messages(task, result, err_messages): if err_messages: task.result = result db().add(task) db().commit() full_err_msg = u"\n".join(err_messages) raise errors.NetworkCheckError(full_err_msg)
def __init__(self, task, data): """Collect Network Groups data """ self.cluster = task.cluster self.task = task self.data = data self.net_man = self.cluster.network_manager() self.net_provider = self.cluster.net_provider admin_ng = self.net_man.get_admin_network_group() fields = NetworkGroup.__mapper__.columns.keys() net = NetworkConfigurationSerializer.serialize_network_group( admin_ng, fields) # change Admin name for UI net.update(name='admin (PXE)') self.networks = [net] for ng in self.cluster.network_groups: net = NetworkConfigurationSerializer.serialize_network_group( ng, fields) self.networks.append(net) # merge with data['networks'] if 'networks' in data: for data_net in data['networks']: for net in self.networks: if data_net['id'] == net['id']: net.update(data_net) break else: raise errors.NetworkCheckError( u"Invalid network ID: {0}".format(data_net['id']), add_client=False) self.result = [] self.err_msgs = []
def neutron_check_segmentation_ids(self): """Check neutron segmentation ids check networks VLAN IDs not in Neutron L2 private VLAN ID range for VLAN segmentation only (neutron) """ tagged_nets = dict((n["name"], n["vlan_start"]) for n in filter( lambda n: (n["vlan_start"] is not None), self.networks)) if tagged_nets: if self.task.cluster.network_config.segmentation_type == \ consts.NEUTRON_SEGMENT_TYPES.vlan: # check networks tags not in Neutron L2 private VLAN ID range vrange = self.network_config['vlan_range'] net_intersect = [ name for name, vlan in tagged_nets.iteritems() if vrange[0] <= vlan <= vrange[1] ] if net_intersect: nets_with_errors = ", ". \ join(net_intersect) err_msg = u"VLAN tags of {0} network(s) intersect with " \ u"VLAN ID range defined for Neutron L2. " \ u"Networks VLAN tags must not intersect " \ u"with Neutron L2 VLAN ID range.". \ format(nets_with_errors) raise errors.NetworkCheckError(err_msg)
def _check_public_network(cls, task): all_public = \ objects.Cluster.should_assign_public_to_all_nodes(task.cluster) public_networks = filter( lambda ng: ng.name == 'public', task.cluster.network_groups) for public in public_networks: nodes = objects.NodeCollection.get_by_group_id(public.group_id) if all_public: nodes_count = nodes.count() else: nodes_count = sum(int(objects.Node.should_have_public(node)) for node in nodes) vip_count = 0 if task.cluster.is_ha_mode and ( any('controller' in node.all_roles for node in nodes) ): # 2 IPs are required for VIPs (1 for haproxy + 1 for vrouter) vip_count = 2 if cls.__network_size(public) < nodes_count + vip_count: error_message = cls.__format_network_error(public, nodes_count) raise errors.NetworkCheckError(error_message)
def neutron_check_segmentation_ids(self): """1. check networks VLAN IDs not in Neutron L2 private VLAN ID range for VLAN segmentation only 2. check networks VLAN IDs should not intersect (neutron) """ tagged_nets = dict((n["name"], n["vlan_start"]) for n in filter( lambda n: (n["vlan_start"] is not None), self.networks)) if tagged_nets: if self.task.cluster.net_segment_type == 'vlan': # check networks tags not in Neutron L2 private VLAN ID range if 'neutron_parameters' in self.data: l2cfg = self.data['neutron_parameters']['L2'] else: l2cfg = self.task.cluster.neutron_config.L2 for net, net_conf in l2cfg['phys_nets'].iteritems(): vrange = net_conf['vlan_range'] if vrange: break else: err_msg = u"Wrong VLAN range for Neutron L2.\n" raise errors.NetworkCheckError(err_msg) net_intersect = [name for name, vlan in tagged_nets.iteritems() if vrange[0] <= vlan <= vrange[1]] if net_intersect: nets_with_errors = ", ". \ join(net_intersect) err_msg = u"VLAN tags of {0} network(s) intersect with " \ u"VLAN ID range defined for Neutron L2. " \ u"Networks VLAN tags must not intersect " \ u"with Neutron L2 VLAN ID range.". \ format(nets_with_errors) raise errors.NetworkCheckError(err_msg) # check networks VLAN IDs should not intersect net_intersect = [name for name, vlan in tagged_nets.iteritems() if tagged_nets.values().count(vlan) >= 2] if net_intersect: err_msg = u"{0} networks use the same VLAN tags. " \ u"You should assign different VLAN tag " \ u"to every network.".format(", ".join(net_intersect)) raise errors.NetworkCheckError(err_msg)
def __check_network(cls, task): nodes_count = len(task.cluster.nodes) public_network = filter(lambda ng: ng.name == 'public', task.cluster.network_groups)[0] public_network_size = cls.__network_size(public_network) if public_network_size < nodes_count: error_message = cls.__format_network_error(nodes_count) raise errors.NetworkCheckError(error_message)
def __init__(self, task, data): """Collect Network Groups data """ self.cluster = task.cluster self.task = task self.data = data self.net_man = objects.Cluster.get_network_manager(self.cluster) #NetworkManager,NeutronManager,NovaNetworkManager self.net_provider = self.cluster.net_provider #net_provider列的值(枚举) admin_ng = self.net_man.get_admin_network_group() #1.admin_ngs = db().query(NetworkGroup).filter_by(name="fuelweb_admin") #2.admin_ng = admin_ng or admin_ngs.filter_by(group_id=None).first() fields = NetworkGroup.__mapper__.columns.keys() + ['meta'] net = NetworkConfigurationSerializer.serialize_network_group(admin_ng, fields) # change Admin name for UI net.update(name='admin (PXE)') self.networks = [net] for ng in self.cluster.network_groups: net = NetworkConfigurationSerializer.serialize_network_group( ng, fields) self.networks.append(net) # merge with data['networks'] logger.info(data) if 'networks' in data: for data_net in data['networks']: for net in self.networks: if data_net['id'] == net['id']: if data_net.get('meta'): data_net.pop('meta') net.update(data_net) if data_net.get('name') == 'fuelweb_admin': net.update(name='admin (PXE)') break else: raise errors.NetworkCheckError( u"Invalid network ID: {0}".format(data_net['id'])) # get common networking parameters serializer = {'neutron': NeutronNetworkConfigurationSerializer, 'nova_network': NovaNetworkConfigurationSerializer} self.network_config = serializer[self.net_provider].\ serialize_network_params(self.cluster) self.network_config.update(data.get('networking_parameters', {})) self.result = [] self.err_msgs = []
def check_vlan_ids_intersection(self): """Networks VLAN IDs should not intersect for any node's interface.""" if self.cluster.network_config.configuration_template is not None: # TODO(akasatkin) checking of network templates to be considered return tagged_nets = dict((n["id"], n["vlan_start"]) for n in filter( lambda n: (n["vlan_start"] is not None), self.networks)) # nothing to check if len(tagged_nets) < 2: return nodes_networks = \ objects.Cluster.get_networks_to_interfaces_mapping_on_all_nodes( self.cluster) # first, group by hostname for node_name, data in groupby(nodes_networks, lambda x: x[0]): # then group by interface name for particular node for if_name, nic_nets in groupby(data, lambda x: x[1]): net_ids = [ net_id for _, _, net_id in nic_nets if net_id in tagged_nets ] if len(net_ids) < 2: # no more than 1 tagged network is on the interface continue vlan_ids = [tagged_nets[n] for n in net_ids] if len(set(vlan_ids)) < len(vlan_ids): # some VLAN IDs are not unique for this interface seen_vlan_ids = set() duplicate_net_ids = set() for idx in range(len(vlan_ids)): if vlan_ids[idx] in seen_vlan_ids: duplicate_net_ids.add(net_ids[idx]) seen_vlan_ids.add(vlan_ids[idx]) net_names = [ net['name'] for net in self.networks if net['id'] in duplicate_net_ids ] err_msg = u"Node {0}, interface {1}: {2} networks use " \ u"the same VLAN tags. Different VLAN tags should be " \ u"assigned to the networks on the same interface.".\ format(node_name, if_name, ", ".join(net_names)) raise errors.NetworkCheckError(err_msg)
def neutron_check_interface_mapping(self): """Check mapping of networks to NICs (Neutron) """ # check untagged networks intersection untagged_nets = set( n["id"] for n in filter( lambda n: (n['vlan_start'] is None) and (not n['meta'].get('neutron_vlan_range')), self.networks)) if untagged_nets: logger.info( "Untagged networks found, " "checking intersection between them...") interfaces = [] for node in self.cluster.nodes: for iface in node.interfaces: interfaces.append(iface) found_intersection = [] for iface in interfaces: nets = dict( (n.id, n.name) for n in iface.assigned_networks_list) crossed_nets = set(nets.keys()) & untagged_nets if len(crossed_nets) > 1: err_net_names = [ '"{0}"'.format(nets[i]) for i in crossed_nets] found_intersection.append( [iface.node.name, err_net_names]) if found_intersection: nodes_with_errors = [ u'Node "{0}": {1}'.format( name, ", ".join(_networks) ) for name, _networks in found_intersection] err_msg = u"Some untagged networks are " \ "assigned to the same physical interface. " \ "You should assign them to " \ "different physical interfaces:\n{0}". \ format("\n".join(nodes_with_errors)) raise errors.NetworkCheckError(err_msg)
def neutron_check_interface_mapping(self): # check if there any networks # on the same interface as admin network (main) admin_interfaces = map(lambda node: node.admin_interface, self.cluster.nodes) found_intersection = [] all_roles = set( [n["id"] for n in self.networks if n != self.networks[0]]) for iface in admin_interfaces: nets = dict((n.id, n.name) for n in iface.assigned_networks) err_nets = set(nets.keys()) & all_roles if err_nets: err_net_names = ['"{0}"'.format(nets[i]) for i in err_nets] found_intersection.append([iface.node.name, err_net_names]) if found_intersection: nodes_with_errors = [ u'Node "{0}": {1}'.format(name, ", ".join(_networks)) for name, _networks in found_intersection ] err_msg = u"Some networks are " \ "assigned to the same physical interface as " \ "admin (PXE) network. You should move them to " \ "another physical interfaces:\n{0}". \ format("\n".join(nodes_with_errors)) raise errors.NetworkCheckError(err_msg, add_client=False) # check if there any networks # on the same interface as private network (for vlan) if self.cluster.net_segment_type == 'vlan': private_interfaces = [] # there should be shorter method to do this ! for node in self.cluster.nodes: for iface in node.interfaces: for anet in iface.assigned_networks: if anet.name == 'private': private_interfaces.append(iface) found_intersection = [] all_roles = set(n["id"] for n in self.networks if n["name"] != 'private') for iface in private_interfaces: nets = dict((n.id, n.name) for n in iface.assigned_networks) err_nets = set(nets.keys()) & all_roles if err_nets: err_net_names = ['"{0}"'.format(nets[i]) for i in err_nets] found_intersection.append([iface.node.name, err_net_names]) if found_intersection: nodes_with_errors = [ u'Node "{0}": {1}'.format(name, ", ".join(_networks)) for name, _networks in found_intersection ] err_msg = u"Some networks are " \ "assigned to the same physical interface as " \ "private network. You should move them to " \ "another physical interfaces:\n{0}". \ format("\n".join(nodes_with_errors)) raise errors.NetworkCheckError(err_msg, add_client=False) # check untagged networks intersection untagged_nets = set(n["id"] for n in filter( lambda n: (n["vlan_start"] is None), self.networks)) if untagged_nets: logger.info("Untagged networks found, " "checking intersection between them...") interfaces = [] for node in self.cluster.nodes: for iface in node.interfaces: interfaces.append(iface) found_intersection = [] for iface in interfaces: nets = dict((n.id, n.name) for n in iface.assigned_networks) crossed_nets = set(nets.keys()) & untagged_nets if len(crossed_nets) > 1: err_net_names = [ '"{0}"'.format(nets[i]) for i in crossed_nets ] found_intersection.append([iface.node.name, err_net_names]) if found_intersection: nodes_with_errors = [ u'Node "{0}": {1}'.format(name, ", ".join(_networks)) for name, _networks in found_intersection ] err_msg = u"Some untagged networks are " \ "assigned to the same physical interface. " \ "You should assign them to " \ "different physical interfaces:\n{0}". \ format("\n".join(nodes_with_errors)) raise errors.NetworkCheckError(err_msg, add_client=False)
def neutron_check_config(self): # check: networks VLAN IDs should not be in # Neutron L2 private VLAN ID range (VLAN segmentation only) tagged_nets = dict((n["name"], n["vlan_start"]) for n in filter( lambda n: (n["vlan_start"] is not None), self.networks)) if tagged_nets: if self.cluster.net_segment_type == 'vlan': if 'neutron_parameters' in self.data: l2cfg = self.data['neutron_parameters']['L2'] else: l2cfg = self.cluster.neutron_config.L2 for net, net_conf in l2cfg['phys_nets'].iteritems(): vrange = net_conf['vlan_range'] if vrange: break else: err_msg = u"Wrong VLAN range.\n" raise errors.NetworkCheckError(err_msg, add_client=False) net_intersect = [ name for name, vlan in tagged_nets.iteritems() if vrange[0] <= vlan <= vrange[1] ] if net_intersect: nets_with_errors = ", ". \ join(net_intersect) err_msg = u"Networks VLAN tags are in " \ "ID range defined for Neutron L2. " \ "You should assign VLAN tags that are " \ "not in Neutron L2 VLAN ID range:\n{0}". \ format(nets_with_errors) raise errors.NetworkCheckError(err_msg, add_client=False) # check: networks VLAN IDs should not intersect net_intersect = [ name for name, vlan in tagged_nets.iteritems() if tagged_nets.values().count(vlan) >= 2 ] if net_intersect: nets_with_errors = ", ". \ join(net_intersect) err_msg = u"Some networks use the same VLAN tags. " \ "You should assign different VLAN tag " \ "to every network:\n{0}". \ format(nets_with_errors) raise errors.NetworkCheckError(err_msg, add_client=False) # check intersection of address ranges # between admin networks and all other networks admin_ng = self.net_man.get_admin_network_group() admin_range = netaddr.IPNetwork(admin_ng.cidr) for ng in self.networks[1:]: net_errors = [] sub_ranges = [] ng_db = db().query(NetworkGroup).get(ng['id']) if not ng_db: net_errors.append("id") self.err_msgs.append("Invalid network ID: {0}".format( ng['id'])) else: if ng.get('cidr'): fnet = netaddr.IPNetwork(ng['cidr']) if self.net_man.is_range_intersection(fnet, admin_range): net_errors.append("cidr") self.err_msgs.append(u"Intersection with admin " "network(s) '{0}' found".format( admin_ng.cidr)) # ng['amount'] is always equal 1 for Neutron if fnet.size < ng['network_size']: # * ng['amount']: net_errors.append("cidr") self.err_msgs.append(u"CIDR size for network '{0}' " "is less than required".format( ng.get('name') or ng_db.name or ng_db.id)) # Check for intersection with Admin network if 'ip_ranges' in ng: for k, v in enumerate(ng['ip_ranges']): ip_range = netaddr.IPRange(v[0], v[1]) if self.net_man.is_range_intersection( admin_range, ip_range): net_errors.append("cidr") self.err_msgs.append( u"IP range {0} - {1} in {2} network intersects" " with admin range of {3}".format( v[0], v[1], ng.get('name') or ng_db.name or ng_db.id, admin_ng.cidr)) sub_ranges.append(k) if net_errors: self.result.append({ "id": int(ng["id"]), "range_errors": sub_ranges, "errors": net_errors }) self.expose_error_messages() # check intersection of address ranges # between networks except admin network ng_names = dict((ng['id'], ng['name']) for ng in self.networks) ngs = list(self.networks) for ng1 in self.networks: net_errors = [] ngs.remove(ng1) for ng2 in ngs: if ng1.get('cidr') and ng2.get('cidr'): cidr1 = netaddr.IPNetwork(ng1['cidr']) cidr2 = netaddr.IPNetwork(ng2['cidr']) if self.net_man.is_cidr_intersection(cidr1, cidr2): net_errors.append("cidr") self.err_msgs.append( u"Intersection between network address " "spaces found:\n{0}".format(", ".join( [ng_names[ng1['id']], ng_names[ng2['id']]]))) if net_errors: self.result.append({ "id": int(ng1["id"]), "errors": net_errors }) self.expose_error_messages() # check Public gateway, Floating Start and Stop IPs # belong to Public CIDR if 'neutron_parameters' in self.data: pre_net = self.data['neutron_parameters']['predefined_networks'] else: pre_net = self.cluster.neutron_config.predefined_networks public = [n for n in self.networks if n['name'] == 'public'][0] net_errors = [] fl_range = pre_net['net04_ext']['L3']['floating'] if public.get('cidr') and public.get('gateway'): cidr = netaddr.IPNetwork(public['cidr']) if netaddr.IPAddress(public['gateway']) not in cidr: net_errors.append("gateway") self.err_msgs.append(u"Public gateway {0} is not in Public " "address space {1}.".format( public['gateway'], public['cidr'])) if netaddr.IPRange(fl_range[0], fl_range[1]) not in cidr: net_errors.append("float_range") self.err_msgs.append( u"Floating address range {0}:{1} is not in Public " "address space {2}.".format(netaddr.IPAddress(fl_range[0]), netaddr.IPAddress(fl_range[1]), public['cidr'])) else: net_errors.append("format") self.err_msgs.append( u"Public gateway or CIDR specification is invalid.") self.result = {"id": int(public["id"]), "errors": net_errors} self.expose_error_messages() # check internal Gateway is in Internal CIDR internal = pre_net['net04']['L3'] if internal.get('cidr') and internal.get('gateway'): cidr = netaddr.IPNetwork(internal['cidr']) if netaddr.IPAddress(internal['gateway']) not in cidr: net_errors.append("gateway") self.err_msgs.append( u"Internal gateway {0} is not in Internal " "address space {1}.".format(internal['gateway'], internal['cidr'])) if self.net_man.is_range_intersection( netaddr.IPRange(fl_range[0], fl_range[1]), cidr): net_errors.append("cidr") self.err_msgs.append( u"Intersection between Internal CIDR and Floating range.") else: net_errors.append("format") self.err_msgs.append( u"Internal gateway or CIDR specification is invalid.") self.result = {"name": "internal", "errors": net_errors} self.expose_error_messages()
def execute(self, task, data, check_admin_untagged=False): # If not set in data then fetch from db if 'net_manager' in data: netmanager = data['net_manager'] else: netmanager = task.cluster.net_manager if 'networks' in data: networks = data['networks'] else: networks = map(lambda x: x.__dict__, task.cluster.network_groups) result = [] err_msgs = [] if check_admin_untagged: # checking if there are untagged networks on the same interface # (main) as admin network untagged_nets = set( n["id"] for n in filter(lambda n: (n["vlan_start"] is None), networks)) if untagged_nets: logger.info("Untagged networks found, " "checking admin network intersection...") main_ifaces = (db().query(NodeNICInterface).get( NetworkManager().get_main_nic(n.id)) for n in task.cluster.nodes) found_intersection = [] for iface in main_ifaces: nets = dict( (n.id, n.name) for n in iface.assigned_networks) err_nets = set(nets.keys()) & untagged_nets if err_nets: err_net_names = [ '"{0}"'.format(nets[i]) for i in err_nets ] found_intersection.append( [iface.node.name, err_net_names]) if found_intersection: nodes_with_errors = [ u'Node "{0}": {1}'.format(name, ", ".join(_networks)) for name, _networks in found_intersection ] err_msg = u"Some untagged networks are " \ "assigned to the same physical interface as " \ "admin (PXE) network. You can whether turn " \ "on tagging for these OpenStack " \ "networks or move them to another physical " \ "interface:\n{0}".format("\n".join( nodes_with_errors )) raise errors.NetworkCheckError(err_msg, add_client=False) admin_ng = NetworkManager().get_admin_network_group() admin_range = netaddr.IPNetwork(admin_ng.cidr) for ng in networks: net_errors = [] sub_ranges = [] ng_db = db().query(NetworkGroup).get(ng['id']) if not ng_db: net_errors.append("id") err_msgs.append("Invalid network ID: {0}".format(ng['id'])) else: if 'cidr' in ng: fnet = netaddr.IPNetwork(ng['cidr']) if NetworkManager().is_range_in_cidr(fnet, admin_range): net_errors.append("cidr") err_msgs.append("Intersection with admin " "network(s) '{0}' found".format( admin_ng.cidr)) if fnet.size < ng['network_size'] * ng['amount']: net_errors.append("cidr") err_msgs.append("CIDR size for network '{0}' " "is less than required".format( ng.get('name') or ng_db.name or ng_db.id)) # Check for intersection with Admin network if 'ip_ranges' in ng: for k, v in enumerate(ng['ip_ranges']): ip_range = netaddr.IPRange(v[0], v[1]) if NetworkManager().is_range_in_cidr( admin_range, ip_range): net_errors.append("cidr") err_msgs.append( "IP range {0} - {1} in {2} network intersects " "with admin range of {3}".format( v[0], v[1], ng.get('name') or ng_db.name or ng_db.id, admin_ng.cidr)) sub_ranges.append(k) if ng.get('amount') > 1 and netmanager == 'FlatDHCPManager': net_errors.append("amount") err_msgs.append("Network amount for '{0}' is more than 1 " "while using FlatDHCP manager.".format( ng.get('name') or ng_db.name or ng_db.id)) if net_errors: result.append({ "id": int(ng["id"]), "range_errors": sub_ranges, "errors": net_errors }) if err_msgs: task.result = result db().add(task) db().commit() full_err_msg = "\n".join(err_msgs) raise errors.NetworkCheckError(full_err_msg)
def execute(self, task, data): task_uuid = task.uuid # If not set in data then fetch from db if 'net_manager' in data: netmanager = data['net_manager'] else: netmanager = task.cluster.net_manager if 'networks' in data: networks = data['networks'] else: networks = map(lambda x: x.__dict__, task.cluster.network_groups) result = [] err_msgs = [] for ng in networks: net_errors = [] ng_db = orm().query(NetworkGroup).get(ng['id']) if not ng_db: net_errors.append("id") err_msgs.append("Invalid network ID: {0}".format(ng['id'])) else: if 'cidr' in ng: fnet = netaddr.IPSet([ng['cidr']]) if fnet & netaddr.IPSet(settings.NET_EXCLUDE): net_errors.append("cidr") err_msgs.append( "Intersection with admin " "network(s) '{0}' found".format( settings.NET_EXCLUDE ) ) if fnet.size < ng['network_size'] * ng['amount']: net_errors.append("cidr") err_msgs.append( "CIDR size for network '{0}' " "is less than required".format( ng.get('name') or ng_db.name or ng_db.id ) ) if ng.get('amount') > 1 and netmanager == 'FlatDHCPManager': net_errors.append("amount") err_msgs.append( "Network amount for '{0}' is more than 1 " "while using FlatDHCP manager.".format( ng.get('name') or ng_db.name or ng_db.id ) ) if net_errors: result.append({ "id": int(ng["id"]), "errors": net_errors }) if err_msgs: task.result = result orm().add(task) orm().commit() full_err_msg = "\n".join(err_msgs) raise errors.NetworkCheckError(full_err_msg)