From 76a0bc226e07b68457a3ce3d9778c2c7245527f5 Mon Sep 17 00:00:00 2001 From: Ryan Moe Date: Tue, 26 Apr 2016 09:34:07 -0700 Subject: [PATCH] Move network manager calls into callbacks Calls to network manager from object methods have been moved into callbacks implemented by the network manager extension. This commit makes the following new callbacks available to extensions: * on_cluster_create: called when a new cluster is created * on_cluster_patch_attributes: called when a cluster's attributes are updated * on_nodegroup_create: called when a node group is created * on_before_deployment_serialization: called before deployment serialization begins * on_before_provisioning_serialization: called before provisioning serialization begins * on_remove_node_from_cluster: called when a node is removed from a cluster Blueprint: network-manager-extension Change-Id: I9a3413f54c881edd098e623ea204d12a86695f87 --- nailgun/nailgun/extensions/__init__.py | 9 + nailgun/nailgun/extensions/base.py | 30 +++ nailgun/nailgun/extensions/manager.py | 36 ++++ .../extensions/network_manager/checker.py | 6 +- .../extensions/network_manager/extension.py | 83 ++++++++ .../extensions/network_manager/manager.py | 29 ++- .../network_manager/managers/neutron.py | 4 +- .../network_manager/objects/bond.py | 16 ++ .../network_manager/objects/interface.py | 94 +++++++++ .../network_manager/objects/ip_addr.py | 55 +++++ .../network_manager/objects/network_group.py | 103 ++++++++++ .../tests/test_network_manager.py | 6 +- .../network_manager/tests/test_objects.py | 21 ++ nailgun/nailgun/objects/cluster.py | 162 ++------------- nailgun/nailgun/objects/node.py | 191 +----------------- nailgun/nailgun/objects/node_group.py | 21 +- .../orchestrator/deployment_serializers.py | 7 +- .../orchestrator/neutron_serializers.py | 2 +- .../orchestrator/provisioning_serializers.py | 6 +- nailgun/nailgun/test/unit/test_objects.py | 21 -- 20 files changed, 513 insertions(+), 389 deletions(-) diff --git a/nailgun/nailgun/extensions/__init__.py b/nailgun/nailgun/extensions/__init__.py index 0c7cd6b1ad..318542905d 100644 --- a/nailgun/nailgun/extensions/__init__.py +++ b/nailgun/nailgun/extensions/__init__.py @@ -24,7 +24,16 @@ from nailgun.extensions.manager import fire_callback_on_node_collection_delete from nailgun.extensions.manager import fire_callback_on_node_create from nailgun.extensions.manager import fire_callback_on_node_update from nailgun.extensions.manager import fire_callback_on_node_reset +from nailgun.extensions.manager import fire_callback_on_nodegroup_create +from nailgun.extensions.manager import fire_callback_on_cluster_create from nailgun.extensions.manager import fire_callback_on_cluster_delete +from nailgun.extensions.manager import fire_callback_on_remove_node_from_cluster +from nailgun.extensions.manager import \ + fire_callback_on_before_deployment_serialization +from nailgun.extensions.manager import \ + fire_callback_on_before_provisioning_serialization +from nailgun.extensions.manager import \ + fire_callback_on_cluster_patch_attributes from nailgun.extensions.manager import \ fire_callback_on_deployment_data_serialization from nailgun.extensions.manager import \ diff --git a/nailgun/nailgun/extensions/base.py b/nailgun/nailgun/extensions/base.py index 0b242625c5..cdaeb28db7 100644 --- a/nailgun/nailgun/extensions/base.py +++ b/nailgun/nailgun/extensions/base.py @@ -121,10 +121,30 @@ class BaseExtension(object): def on_node_delete(cls, node): """Callback which gets executed when node is deleted""" + @classmethod + def on_remove_node_from_cluster(cls, node): + """Callback which gets executed when node is removed from a cluster""" + @classmethod def on_node_collection_delete(cls, node_ids): """Callback which gets executed when node collection is deleted""" + @classmethod + def on_nodegroup_create(cls, nodegroup): + """Callback which gets executed when node group is created""" + + @classmethod + def on_cluster_create(cls, cluster, data): + """Callback which gets executed when cluster is initially created. + + This is called after the cluster object is created, attributes have + been created and the default extensions list has been set. + """ + + @classmethod + def on_cluster_patch_attributes(cls, cluster, public_map): + """Callback which gets executed when cluster attributes are updated""" + @classmethod def on_cluster_delete(cls, cluster): """Callback which gets executed when cluster is deleted""" @@ -132,3 +152,13 @@ class BaseExtension(object): @classmethod def on_before_deployment_check(cls, cluster): """Callback which gets executed when "before deployment check" runs""" + + @classmethod + def on_before_deployment_serialization(cls, cluster, nodes, + ignore_customized): + """Callback which gets executed before deployment serialization""" + + @classmethod + def on_before_provisioning_serialization(cls, cluster, nodes, + ignore_customized): + """Callback which gets executed before provisioning serialization""" diff --git a/nailgun/nailgun/extensions/manager.py b/nailgun/nailgun/extensions/manager.py index 1a4ae05267..6a0a7c7866 100644 --- a/nailgun/nailgun/extensions/manager.py +++ b/nailgun/nailgun/extensions/manager.py @@ -96,11 +96,31 @@ def fire_callback_on_node_delete(node): extension.on_node_delete(node) +def fire_callback_on_remove_node_from_cluster(node): + for extension in get_all_extensions(): + extension.on_remove_node_from_cluster(node) + + def fire_callback_on_node_collection_delete(node_ids): for extension in get_all_extensions(): extension.on_node_collection_delete(node_ids) +def fire_callback_on_nodegroup_create(nodegroup): + for extension in get_all_extensions(): + extension.on_nodegroup_create(nodegroup) + + +def fire_callback_on_cluster_create(cluster, data): + for extension in get_all_extensions(): + extension.on_cluster_create(cluster, data) + + +def fire_callback_on_cluster_patch_attributes(cluster, public_map): + for extension in get_all_extensions(): + extension.on_cluster_patch_attributes(cluster, public_map) + + def fire_callback_on_cluster_delete(cluster): for extension in get_all_extensions(): extension.on_cluster_delete(cluster) @@ -111,6 +131,22 @@ def fire_callback_on_before_deployment_check(cluster): extension.on_before_deployment_check(cluster) +def fire_callback_on_before_deployment_serialization(cluster, nodes, + ignore_customized): + for extension in get_all_extensions(): + extension.on_before_deployment_serialization( + cluster, nodes, ignore_customized + ) + + +def fire_callback_on_before_provisioning_serialization(cluster, nodes, + ignore_customized): + for extension in get_all_extensions(): + extension.on_before_provisioning_serialization( + cluster, nodes, ignore_customized + ) + + def _collect_data_pipelines_for_cluster(cluster): extensions = set(cluster.extensions) return chain.from_iterable(e.data_pipelines for e in get_all_extensions() diff --git a/nailgun/nailgun/extensions/network_manager/checker.py b/nailgun/nailgun/extensions/network_manager/checker.py index 9caecf94ec..aef88e5bbd 100644 --- a/nailgun/nailgun/extensions/network_manager/checker.py +++ b/nailgun/nailgun/extensions/network_manager/checker.py @@ -103,11 +103,11 @@ class NetworkCheck(object): "checking intersection between them...") bond_interfaces = ( - objects.Cluster.get_bond_interfaces_for_all_nodes( + objects.Bond.get_bond_interfaces_for_all_nodes( self.cluster, untagged_nets.keys())) nic_interfaces = ( - objects.Cluster.get_nic_interfaces_for_all_nodes( + objects.NIC.get_nic_interfaces_for_all_nodes( self.cluster, untagged_nets.keys())) found_intersection = [] @@ -706,7 +706,7 @@ class NetworkCheck(object): return nodes_networks = \ - objects.Cluster.get_networks_to_interfaces_mapping_on_all_nodes( + objects.NIC.get_networks_to_interfaces_mapping_on_all_nodes( self.cluster) # first, group by hostname diff --git a/nailgun/nailgun/extensions/network_manager/extension.py b/nailgun/nailgun/extensions/network_manager/extension.py index 3e73b104e0..b709df9903 100644 --- a/nailgun/nailgun/extensions/network_manager/extension.py +++ b/nailgun/nailgun/extensions/network_manager/extension.py @@ -1,3 +1,5 @@ +from nailgun import consts +from nailgun import errors from nailgun.extensions import BaseExtension from nailgun.extensions.network_manager.handlers.network_configuration import\ NetworkAttributesDeployedHandler @@ -29,6 +31,8 @@ from nailgun.extensions.network_manager.handlers.nic import \ from nailgun.extensions.network_manager.handlers.nic import \ NodeNICsHandler +from nailgun import objects + class NetworkManagerExtension(BaseExtension): name = 'network_manager' @@ -74,3 +78,82 @@ class NetworkManagerExtension(BaseExtension): r'deployed?$', 'handler': NetworkAttributesDeployedHandler} ] + + @classmethod + def on_cluster_create(cls, cluster, data): + try: + net_manager = objects.Cluster.get_network_manager(cluster) + net_manager.create_network_groups_and_config(cluster, data) + objects.Cluster.add_pending_changes( + cluster, consts.CLUSTER_CHANGES.networks) + net_manager.assign_vips_for_net_groups(cluster) + except ( + errors.OutOfVLANs, + errors.OutOfIPs, + errors.NoSuitableCIDR, + + # VIP assignment related errors + errors.CanNotFindCommonNodeGroup, + errors.CanNotFindNetworkForNodeGroup, + errors.DuplicatedVIPNames + ) as exc: + raise errors.CannotCreate(exc.message) + + @classmethod + def on_cluster_patch_attributes(cls, cluster, public_map): + + roles_metadata = objects.Cluster.get_roles(cluster) + nm = objects.Cluster.get_network_manager(cluster) + nm.update_restricted_networks(cluster) + objects.NetworkGroup._update_public_network( + cluster, public_map, roles_metadata + ) + + @classmethod + def on_nodegroup_create(cls, ng): + try: + cluster = objects.Cluster.get_by_uid(ng.cluster_id) + nm = objects.Cluster.get_network_manager(cluster) + nst = cluster.network_config.segmentation_type + # We have two node groups here when user adds the first custom + # node group. + if (objects.NodeGroupCollection.get_by_cluster_id(cluster.id) + .count() == 2): + nm.ensure_gateways_present_in_default_node_group(cluster) + nm.create_network_groups( + cluster, neutron_segment_type=nst, node_group_id=ng.id, + set_all_gateways=True) + nm.create_admin_network_group(ng.cluster_id, ng.id) + except ( + errors.OutOfVLANs, + errors.OutOfIPs, + errors.NoSuitableCIDR + ) as exc: + raise errors.CannotCreate(exc.message) + + @classmethod + def on_before_deployment_serialization(cls, cluster, nodes, + ignore_customized): + # TODO(apply only for specified subset of nodes) + nm = objects.Cluster.get_network_manager(cluster) + nm.prepare_for_deployment( + cluster, cluster.nodes if nodes is None else nodes + ) + + @classmethod + def on_before_provisioning_serialization(cls, cluster, nodes, + ignore_customized): + nm = objects.Cluster.get_network_manager(cluster) + nm.prepare_for_provisioning( + cluster.nodes if nodes is None else nodes + ) + + @classmethod + def on_node_reset(cls, node): + objects.IPAddr.delete_by_node(node.id) + + @classmethod + def on_remove_node_from_cluster(cls, node): + netmanager = objects.Cluster.get_network_manager(node.cluster) + netmanager.clear_assigned_networks(node) + netmanager.clear_bond_configuration(node) diff --git a/nailgun/nailgun/extensions/network_manager/manager.py b/nailgun/nailgun/extensions/network_manager/manager.py index 741b13fc07..5b7ef4fee6 100644 --- a/nailgun/nailgun/extensions/network_manager/manager.py +++ b/nailgun/nailgun/extensions/network_manager/manager.py @@ -95,7 +95,7 @@ class NetworkManager(object): node_id = node.id admin_net = objects.NetworkGroup.get_admin_network_group( node, default_admin_net) - node_admin_ips_count = objects.Node.get_network_ips_count( + node_admin_ips_count = objects.IPAddr.get_network_ips_count( node_id, admin_net.id) logger.debug(u"Trying to assign admin ip: node=%s", node_id) if not node_admin_ips_count: @@ -579,7 +579,7 @@ class NetworkManager(object): """ node_group = objects.NodeGroup.get_by_uid(ng.group_id) for node in node_group.nodes: - objects.Node.assign_network_to_interface(node, ng) + objects.NetworkGroup.assign_network_to_interface(ng, node) @classmethod def get_default_interfaces_configuration(cls, node): @@ -1029,9 +1029,26 @@ class NetworkManager(object): @classmethod def get_admin_ip_for_node(cls, node=None, admin_net=None): - """Returns first admin IP address for node.""" + """Returns first admin IP address for node. + + When admin_net_id is None the admin network group for the node's + nodegroup will be used. + + :param node: return admin IP of this node + :type node: nailgun.db.sqlalchemy.models.Node + :param admin_net_id: Admin NetworkGroup ID + :type admin_net_id: int + :returns: IPAddr instance + """ admin_net_id = admin_net.id if admin_net else None - return objects.Node.get_admin_ip(node, admin_net_id) + if not admin_net_id: + admin_net = objects.NetworkGroup.get_admin_network_group(node) + admin_net_id = admin_net.id + + admin_ip = next((ip for ip in node.ip_addrs + if ip.network == admin_net_id), None) + + return getattr(admin_ip, 'ip_addr', None) @classmethod def get_admin_interface(cls, node): @@ -1888,7 +1905,9 @@ class AssignIPs70Mixin(object): nodes_by_id = dict((n.id, n) for n in nodes) - query = objects.Cluster.get_network_groups_and_node_ids(cluster.id) + query = objects.NetworkGroup.get_network_groups_and_node_ids( + cluster.id + ) # Group by NetworkGroup.id for key, items in groupby(query, lambda x: x[1]): diff --git a/nailgun/nailgun/extensions/network_manager/managers/neutron.py b/nailgun/nailgun/extensions/network_manager/managers/neutron.py index 30657958ed..8b7b04a33d 100644 --- a/nailgun/nailgun/extensions/network_manager/managers/neutron.py +++ b/nailgun/nailgun/extensions/network_manager/managers/neutron.py @@ -150,7 +150,7 @@ class NeutronManager70( if not node.group_id: return {} - ngs = objects.Node.get_networks_ips(node) + ngs = objects.IPAddr.get_networks_ips(node) if not ngs: return {} @@ -433,7 +433,7 @@ class NeutronManager70( # not an ethernet interface so no NIC will be found. if values['type'] == consts.NETWORK_INTERFACE_TYPES.ether \ and not is_sub_iface: - nic = objects.Node.get_nic_by_name(node, iface) + nic = objects.NIC.get_nic_by_name(node, iface) # NIC names in the template, that networks should be # assigned to, might not be consistent with names of actually diff --git a/nailgun/nailgun/extensions/network_manager/objects/bond.py b/nailgun/nailgun/extensions/network_manager/objects/bond.py index f02e7250ed..31f227c56f 100644 --- a/nailgun/nailgun/extensions/network_manager/objects/bond.py +++ b/nailgun/nailgun/extensions/network_manager/objects/bond.py @@ -15,6 +15,7 @@ # under the License. +from nailgun.db import db from nailgun.db.sqlalchemy import models from nailgun.extensions.network_manager.objects.interface import DPDKMixin from nailgun.extensions.network_manager.objects.interface import NIC @@ -57,6 +58,21 @@ class Bond(DPDKMixin, NailgunObject): return all(NIC.get_dpdk_driver(iface, dpdk_drivers) for iface in instance.slaves) + @classmethod + def get_bond_interfaces_for_all_nodes(cls, cluster, networks=None): + bond_interfaces_query = db().query( + models.NodeBondInterface + ).join( + models.Node + ).filter( + models.Node.cluster_id == cluster.id + ) + if networks: + bond_interfaces_query = bond_interfaces_query.join( + models.NodeBondInterface.assigned_networks_list, + aliased=True).filter(models.NetworkGroup.id.in_(networks)) + return bond_interfaces_query.all() + class BondCollection(NailgunCollection): diff --git a/nailgun/nailgun/extensions/network_manager/objects/interface.py b/nailgun/nailgun/extensions/network_manager/objects/interface.py index 2dd40222fc..1627ffa8e0 100644 --- a/nailgun/nailgun/extensions/network_manager/objects/interface.py +++ b/nailgun/nailgun/extensions/network_manager/objects/interface.py @@ -117,6 +117,100 @@ class NIC(DPDKMixin, NailgunObject): mode["state"] = old_modes_states[mode["name"]] instance.offloading_modes = new_modes + @classmethod + def get_nic_interfaces_for_all_nodes(cls, cluster, networks=None): + nic_interfaces_query = db().query( + models.NodeNICInterface + ).join( + models.Node + ).filter( + models.Node.cluster_id == cluster.id + ) + if networks: + nic_interfaces_query = nic_interfaces_query.join( + models.NodeNICInterface.assigned_networks_list, aliased=True).\ + filter(models.NetworkGroup.id.in_(networks)) + return nic_interfaces_query.all() + + @classmethod + def get_networks_to_interfaces_mapping_on_all_nodes(cls, cluster): + """Query networks to interfaces mapping on all nodes in cluster. + + Returns combined results for NICs and bonds for every node. + Names are returned for node and interface (NIC or bond), + IDs are returned for networks. Results are sorted by node name then + interface name. + """ + nodes_nics_networks = db().query( + models.Node.hostname, + models.NodeNICInterface.name, + models.NetworkGroup.id, + ).join( + models.Node.nic_interfaces, + models.NodeNICInterface.assigned_networks_list + ).filter( + models.Node.cluster_id == cluster.id, + ) + nodes_bonds_networks = db().query( + models.Node.hostname, + models.NodeBondInterface.name, + models.NetworkGroup.id, + ).join( + models.Node.bond_interfaces, + models.NodeBondInterface.assigned_networks_list + ).filter( + models.Node.cluster_id == cluster.id, + ) + return nodes_nics_networks.union( + nodes_bonds_networks + ).order_by( + # column 1 then 2 from the result. cannot call them by name as + # names for column 2 are different in this union + '1', '2' + ) + + @classmethod + def get_interface_by_net_name(cls, node_id, netname): + """Get interface with specified network assigned to it. + + This method first checks for a NodeNICInterface with the specified + network assigned. If that fails it will look for a NodeBondInterface + with that network assigned. + + :param instance_id: Node ID + :param netname: NetworkGroup name + :returns: either NodeNICInterface or NodeBondInterface + """ + iface = db().query(models.NodeNICInterface).join( + (models.NetworkGroup, + models.NodeNICInterface.assigned_networks_list) + ).filter( + models.NetworkGroup.name == netname + ).filter( + models.NodeNICInterface.node_id == node_id + ).first() + if iface: + return iface + + return db().query(models.NodeBondInterface).join( + (models.NetworkGroup, + models.NodeBondInterface.assigned_networks_list) + ).filter( + models.NetworkGroup.name == netname + ).filter( + models.NodeBondInterface.node_id == node_id + ).first() + + @classmethod + def get_nic_by_name(cls, node, iface_name): + nic = db().query(models.NodeNICInterface).filter_by( + name=iface_name + ).filter_by( + node_id=node.id + ).first() + + return nic + class NICCollection(NailgunCollection): diff --git a/nailgun/nailgun/extensions/network_manager/objects/ip_addr.py b/nailgun/nailgun/extensions/network_manager/objects/ip_addr.py index a4796802eb..348fb9fe8f 100644 --- a/nailgun/nailgun/extensions/network_manager/objects/ip_addr.py +++ b/nailgun/nailgun/extensions/network_manager/objects/ip_addr.py @@ -145,6 +145,61 @@ class IPAddr(NailgunObject): models.IPAddr.network == network ).delete(synchronize_session='fetch') + @classmethod + def get_networks_ips(cls, node): + """Get IPs assigned to node grouped by network group. + + :param node: Node instance + :returns: query + """ + return db().query( + models.NetworkGroup, models.IPAddr.ip_addr + ).filter( + models.NetworkGroup.group_id == node.group_id, + models.IPAddr.network == models.NetworkGroup.id, + models.IPAddr.node == node.id + ) + + @classmethod + def get_networks_ips_dict(cls, node): + """Get IPs assigned to node grouped by network group. + + :param node: Node instance + :returns: dict mapping network group name to IP addresses + """ + return {ng.name: ip for ng, ip in cls.get_networks_ips(node)} + + @classmethod + def get_network_ips_count(cls, node_id, network_id): + """Get number of IPs from specified network assigned to node. + + :param node_id: Node ID + :param network_id: NetworkGroup ID + :returns: count of IP addresses + """ + return db().query(models.IPAddr).filter_by( + node=node_id, network=network_id).count() + + @classmethod + def set_networks_ips(cls, node, ips_by_network_name): + """Set IPs by provided network-to-IP mapping. + + :param instance: Node instance + :param ips_by_network_name: dict + :returns: None + """ + ngs = db().query( + models.NetworkGroup.name, models.IPAddr + ).filter( + models.NetworkGroup.group_id == node.group_id, + models.IPAddr.network == models.NetworkGroup.id, + models.IPAddr.node == node.id, + models.NetworkGroup.name.in_(ips_by_network_name) + ) + for ng_name, ip_addr in ngs: + ip_addr.ip_addr = ips_by_network_name[ng_name] + db().flush() + class IPAddrRange(NailgunObject): model = models.IPAddrRange diff --git a/nailgun/nailgun/extensions/network_manager/objects/network_group.py b/nailgun/nailgun/extensions/network_manager/objects/network_group.py index 0511c17768..f8a102264a 100644 --- a/nailgun/nailgun/extensions/network_manager/objects/network_group.py +++ b/nailgun/nailgun/extensions/network_manager/objects/network_group.py @@ -345,6 +345,109 @@ class NetworkGroup(NailgunObject): return network + @classmethod + def get_network_groups_and_node_ids(cls, cluster_id): + """Get network group information for the given cluster + + The admin network group will not be included. + + :param instance: Cluster instance + :type instance: nailgun.db.sqlalchemy.models.Cluster instance + :returns: tuple of Node ID, and NetworkGroup ID, name, meta + """ + query = (db().query( + models.Node.id, + models.NetworkGroup.id, + models.NetworkGroup.name, + models.NetworkGroup.meta) + .join(models.NodeGroup.nodes) + .join(models.NodeGroup.networks) + .filter(models.NodeGroup.cluster_id == cluster_id, + models.NetworkGroup.name != consts.NETWORKS.fuelweb_admin) + ) + + return query + + @classmethod + def _update_public_network(cls, cluster, public_map, roles_metadata): + """Applies changes to node's public_network checked using public_map. + + :param instance: Cluster object + :param public_map: dict of Node.id to should_have_public result. + :param roles_metadata: dict from objects.Cluster.get_roles + """ + + if cluster.network_config.configuration_template is not None: + return + from nailgun.objects import Node + for node in cluster.nodes: + should_have_public = Node.should_have_public( + node, roles_metadata) + if public_map.get(node.id) == should_have_public: + continue + if should_have_public: + cls.assign_public_network(node) + else: + cls.unassign_public_network(node) + + @classmethod + def assign_public_network(cls, node): + public_net = next(NetworkGroupCollection.filter_by( + node.nodegroup.networks, + name=consts.NETWORKS.public), None) + cls.assign_network_to_interface(public_net, node) + + @classmethod + def unassign_public_network(cls, node): + from nailgun import objects + public_net = next(NetworkGroupCollection.filter_by( + node.nodegroup.networks, + name=consts.NETWORKS.public), None) + ifaces = objects.Node.get_interfaces_without_bonds_slaves(node) + for iface in ifaces: + network_list = iface.assigned_networks_list + if public_net in network_list: + network_list.remove(public_net) + objects.NIC.assign_networks(iface, network_list) + + @classmethod + def assign_network_to_interface(cls, instance, node): + """Assign network to interface by default for single node + + Assign given network to first available interface. + Checks interface type, if network is already assigned + and already assigned networks. + """ + if instance is None: + return + from nailgun import objects + untagged = cls.is_untagged(instance) + dedicated = instance.meta.get('dedicated_nic') + ifaces = objects.Node.get_interfaces_without_bonds_slaves(node) + for iface in ifaces: + if dedicated and iface.assigned_networks_list: + continue + for net in iface.assigned_networks_list: + if net.meta.get('dedicated_nic'): + break + if net == instance: + return + if untagged and cls.is_untagged(net): + break + else: + assigned_nets = iface.assigned_networks_list + [instance] + objects.NIC.assign_networks(iface, assigned_nets) + break + else: + logger.warning( + "Cannot assign network %r appropriately for " + "node %r. Set unassigned network to the " + "interface %r", + instance.name, node.name, ifaces[0].name + ) + assigned_nets = ifaces[0].assigned_networks_list + [instance] + objects.NIC.assign_networks(ifaces[0], assigned_nets) + class NetworkGroupCollection(NailgunCollection): diff --git a/nailgun/nailgun/extensions/network_manager/tests/test_network_manager.py b/nailgun/nailgun/extensions/network_manager/tests/test_network_manager.py index 710845b366..3df5285369 100644 --- a/nailgun/nailgun/extensions/network_manager/tests/test_network_manager.py +++ b/nailgun/nailgun/extensions/network_manager/tests/test_network_manager.py @@ -617,7 +617,7 @@ class TestNetworkManager(BaseIntegrationTest): (ip.network_data.name, ip.ip_addr) for ip in node.ip_addrs ) self.assertEquals(node_net_ips, - objects.Node.get_networks_ips_dict(node)) + objects.IPAddr.get_networks_ips_dict(node)) def test_get_admin_ip_for_node(self): cluster = self.env.create(api=False) @@ -649,9 +649,9 @@ class TestNetworkManager(BaseIntegrationTest): node_net_ips = \ dict((net.name, self.env.network_manager.get_free_ips(net)[0]) for net in node.networks) - objects.Node.set_networks_ips(node, node_net_ips) + objects.IPAddr.set_networks_ips(node, node_net_ips) self.assertEquals(node_net_ips, - objects.Node.get_networks_ips_dict(node)) + objects.IPAddr.get_networks_ips_dict(node)) def test_set_netgroups_ids(self): cluster = self.env.create_cluster(api=False) diff --git a/nailgun/nailgun/extensions/network_manager/tests/test_objects.py b/nailgun/nailgun/extensions/network_manager/tests/test_objects.py index 812839e253..2a5572049d 100644 --- a/nailgun/nailgun/extensions/network_manager/tests/test_objects.py +++ b/nailgun/nailgun/extensions/network_manager/tests/test_objects.py @@ -19,6 +19,7 @@ import mock from netaddr import IPNetwork from nailgun import consts +from nailgun.db.sqlalchemy.models import NodeBondInterface from nailgun import objects from nailgun.test.base import BaseTestCase @@ -106,6 +107,16 @@ class TestBondObject(BaseTestCase): objects.Bond.update(bond, data) self.assertEqual(data['offloading_modes'], bond.offloading_modes) + def test_get_bond_interfaces_for_all_nodes(self): + node = self.env.nodes[0] + node.bond_interfaces.append( + NodeBondInterface(name='ovs-bond0', + slaves=node.nic_interfaces)) + self.db.flush() + bond_interfaces = objects.Bond.get_bond_interfaces_for_all_nodes( + self.env.clusters[0]) + self.assertEqual(len(bond_interfaces), 1) + class TestNICObject(BaseTestCase): @@ -145,6 +156,16 @@ class TestNICObject(BaseTestCase): self.assertEqual(len(mac_list), 1) self.assertEqual(mac_list[0], expected_mac) + def test_get_nic_interfaces_for_all_nodes(self): + nodes = self.env.nodes + interfaces = [] + for node in nodes: + for inf in node.nic_interfaces: + interfaces.append(inf) + nic_interfaces = objects.NIC.get_nic_interfaces_for_all_nodes( + self.env.clusters[0]) + self.assertEqual(len(nic_interfaces), len(interfaces)) + class TestIPAddrObject(BaseTestCase): diff --git a/nailgun/nailgun/objects/cluster.py b/nailgun/nailgun/objects/cluster.py index 4b7e83a89b..f79043709e 100644 --- a/nailgun/nailgun/objects/cluster.py +++ b/nailgun/nailgun/objects/cluster.py @@ -33,7 +33,9 @@ from nailgun import consts from nailgun.db import db from nailgun.db.sqlalchemy import models from nailgun import errors +from nailgun.extensions import fire_callback_on_cluster_create from nailgun.extensions import fire_callback_on_cluster_delete +from nailgun.extensions import fire_callback_on_cluster_patch_attributes from nailgun.extensions import fire_callback_on_node_collection_delete from nailgun.logger import logger from nailgun.objects import DeploymentGraph @@ -177,36 +179,18 @@ class Cluster(NailgunObject): # default graph should be created in any case DeploymentGraph.create_for_model({"tasks": deployment_tasks}, cluster) - try: - net_manager = cls.get_network_manager(cluster) - net_manager.create_network_groups_and_config(cluster, data) + cls.add_pending_changes( + cluster, consts.CLUSTER_CHANGES.attributes) + cls.add_pending_changes( + cluster, consts.CLUSTER_CHANGES.vmware_attributes) - cls.add_pending_changes( - cluster, consts.CLUSTER_CHANGES.attributes) - cls.add_pending_changes( - cluster, consts.CLUSTER_CHANGES.networks) - cls.add_pending_changes( - cluster, consts.CLUSTER_CHANGES.vmware_attributes) + ClusterPlugins.add_compatible_plugins(cluster) + PluginManager.enable_plugins_by_components(cluster) - if assign_nodes: - cls.update_nodes(cluster, assign_nodes) + fire_callback_on_cluster_create(cluster, data) - ClusterPlugins.add_compatible_plugins(cluster) - PluginManager.enable_plugins_by_components(cluster) - - net_manager.assign_vips_for_net_groups(cluster) - - except ( - errors.OutOfVLANs, - errors.OutOfIPs, - errors.NoSuitableCIDR, - - # VIP assignment related errors - errors.CanNotFindCommonNodeGroup, - errors.CanNotFindNetworkForNodeGroup, - errors.DuplicatedVIPNames - ) as exc: - raise errors.CannotCreate(exc.message) + if assign_nodes: + cls.update_nodes(cluster, assign_nodes) return cluster @@ -405,28 +389,6 @@ class Cluster(NailgunObject): node, roles_metadata) return public_map - @classmethod - def _update_public_network(cls, instance, public_map, roles_metadata): - """Applies changes to node's public_network checked using public_map. - - :param instance: Cluster object - :param public_map: dict of Node.id to should_have_public result. - :param roles_metadata: dict from objects.Cluster.get_roles - """ - - if instance.network_config.configuration_template is not None: - return - from nailgun import objects - for node in instance.nodes: - should_have_public = objects.Node.should_have_public( - node, roles_metadata) - if public_map.get(node.id) == should_have_public: - continue - if should_have_public: - objects.Node.assign_public_network(node) - else: - objects.Node.unassign_public_network(node) - @classmethod def patch_attributes(cls, instance, data): """Applyes changes to Cluster attributes and updates networks. @@ -434,7 +396,6 @@ class Cluster(NailgunObject): :param instance: Cluster object :param data: dict """ - roles_metadata = Cluster.get_roles(instance) # Note(kszukielojc): We need to create status map of public networks # to avoid updating networks if there was no change to node public @@ -445,8 +406,8 @@ class Cluster(NailgunObject): instance.attributes.editable = dict_merge( instance.attributes.editable, data['editable']) cls.add_pending_changes(instance, "attributes") - cls.get_network_manager(instance).update_restricted_networks(instance) - cls._update_public_network(instance, public_map, roles_metadata) + + fire_callback_on_cluster_patch_attributes(instance, public_map) db().flush() @classmethod @@ -696,7 +657,7 @@ class Cluster(NailgunObject): db().flush() @classmethod - def get_ifaces_for_network_in_cluster(cls, instance, net): + def get_ifaces_for_network_in_cluster(cls, cluster, net): """Method for receiving node_id:iface pairs for all nodes in cluster :param instance: Cluster instance @@ -708,14 +669,14 @@ class Cluster(NailgunObject): models.NodeNICInterface.node_id, models.NodeNICInterface.name ).filter( - models.NodeNICInterface.node.has(cluster_id=instance.id), + models.NodeNICInterface.node.has(cluster_id=cluster.id), models.NodeNICInterface.assigned_networks_list.any(name=net) ) bonds_db = db().query( models.NodeBondInterface.node_id, models.NodeBondInterface.name ).filter( - models.NodeBondInterface.node.has(cluster_id=instance.id), + models.NodeBondInterface.node.has(cluster_id=cluster.id), models.NodeBondInterface.assigned_networks_list.any(name=net) ) return nics_db.union(bonds_db) @@ -999,26 +960,6 @@ class Cluster(NailgunObject): return nodegroups - @classmethod - def get_bond_interfaces_for_all_nodes(cls, instance, networks=None): - bond_interfaces_query = db().query(models.NodeBondInterface).\ - join(models.Node).filter(models.Node.cluster_id == instance.id) - if networks: - bond_interfaces_query = bond_interfaces_query.join( - models.NodeBondInterface.assigned_networks_list, - aliased=True).filter(models.NetworkGroup.id.in_(networks)) - return bond_interfaces_query.all() - - @classmethod - def get_nic_interfaces_for_all_nodes(cls, instance, networks=None): - nic_interfaces_query = db().query(models.NodeNICInterface).\ - join(models.Node).filter(models.Node.cluster_id == instance.id) - if networks: - nic_interfaces_query = nic_interfaces_query.join( - models.NodeNICInterface.assigned_networks_list, aliased=True).\ - filter(models.NetworkGroup.id.in_(networks)) - return nic_interfaces_query.all() - @classmethod def get_default_group(cls, instance): return next(g for g in instance.node_groups if g.is_default) @@ -1398,43 +1339,6 @@ class Cluster(NailgunObject): return bool(instance.attributes.editable['additional_components']. get((component), {}).get('value')) - @classmethod - def get_networks_to_interfaces_mapping_on_all_nodes(cls, instance): - """Query networks to interfaces mapping on all nodes in cluster. - - Returns combined results for NICs and bonds for every node. - Names are returned for node and interface (NIC or bond), - IDs are returned for networks. Results are sorted by node name then - interface name. - """ - nodes_nics_networks = db().query( - models.Node.hostname, - models.NodeNICInterface.name, - models.NetworkGroup.id, - ).join( - models.Node.nic_interfaces, - models.NodeNICInterface.assigned_networks_list - ).filter( - models.Node.cluster_id == instance.id, - ) - nodes_bonds_networks = db().query( - models.Node.hostname, - models.NodeBondInterface.name, - models.NetworkGroup.id, - ).join( - models.Node.bond_interfaces, - models.NodeBondInterface.assigned_networks_list - ).filter( - models.Node.cluster_id == instance.id, - ) - return nodes_nics_networks.union( - nodes_bonds_networks - ).order_by( - # column 1 then 2 from the result. cannot call them by name as - # names for column 2 are different in this union - '1', '2' - ) - @classmethod def get_nodes_to_update_config(cls, cluster, node_ids=None, node_role=None, only_ready_nodes=True): @@ -1470,17 +1374,6 @@ class Cluster(NailgunObject): instance, instance.nodes if nodes is None else nodes ) - @classmethod - def prepare_for_provisioning(cls, instance, nodes=None): - """Shortcut for NetworkManager.prepare_for_provisioning. - - :param instance: nailgun.db.sqlalchemy.models.Cluster instance - :param nodes: the list of Nodes, None means for all nodes - """ - cls.get_network_manager(instance).prepare_for_provisioning( - instance.nodes if nodes is None else nodes - ) - @classmethod def has_compute_vmware_changes(cls, instance): """Checks if any 'compute-vmware' nodes are waiting for deployment. @@ -1566,29 +1459,6 @@ class Cluster(NailgunObject): q = db().query(models.Node).filter_by(cluster_id=instance.id) return q.filter(models.Node.status != status).count() - @classmethod - def get_network_groups_and_node_ids(cls, instance_id): - """Get network group information for the given cluster - - The admin network group will not be included. - - :param instance: Cluster instance - :type instance: nailgun.db.sqlalchemy.models.Cluster instance - :returns: tuple of Node ID, and NetworkGroup ID, name, meta - """ - query = (db().query( - models.Node.id, - models.NetworkGroup.id, - models.NetworkGroup.name, - models.NetworkGroup.meta) - .join(models.NodeGroup.nodes) - .join(models.NodeGroup.networks) - .filter(models.NodeGroup.cluster_id == instance_id, - models.NetworkGroup.name != consts.NETWORKS.fuelweb_admin) - ) - - return query - @classmethod def get_network_attributes(cls, instance): # use local import to avoid recursive imports diff --git a/nailgun/nailgun/objects/node.py b/nailgun/nailgun/objects/node.py index 44c3bf4126..4bfbab3bed 100644 --- a/nailgun/nailgun/objects/node.py +++ b/nailgun/nailgun/objects/node.py @@ -42,16 +42,15 @@ from nailgun.extensions import fire_callback_on_node_create from nailgun.extensions import fire_callback_on_node_delete from nailgun.extensions import fire_callback_on_node_reset from nailgun.extensions import fire_callback_on_node_update +from nailgun.extensions import fire_callback_on_remove_node_from_cluster from nailgun.extensions.network_manager.template import NetworkTemplate from nailgun.extensions.network_manager import utils as network_utils from nailgun.logger import logger from nailgun.objects import Bond from nailgun.objects import Cluster -from nailgun.objects import IPAddr from nailgun.objects import NailgunCollection from nailgun.objects import NailgunObject from nailgun.objects import NetworkGroup -from nailgun.objects import NetworkGroupCollection from nailgun.objects import NIC from nailgun.objects import Notification from nailgun.objects import Release @@ -76,61 +75,6 @@ class Node(NailgunObject): fire_callback_on_node_delete(instance) super(Node, cls).delete(instance) - @classmethod - def get_network_ips_count(cls, node_id, network_id): - """Get number of IPs from specified network assigned to node. - - :param node_id: Node ID - :param network_id: NetworkGroup ID - :returns: count of IP addresses - """ - return db().query(models.IPAddr).filter_by( - node=node_id, network=network_id).count() - - @classmethod - def get_networks_ips(cls, instance): - """Get IPs assigned to node grouped by network group. - - :param node: Node instance - :returns: query - """ - return db().query( - models.NetworkGroup, models.IPAddr.ip_addr - ).filter( - models.NetworkGroup.group_id == instance.group_id, - models.IPAddr.network == models.NetworkGroup.id, - models.IPAddr.node == instance.id - ) - - @classmethod - def get_networks_ips_dict(cls, instance): - """Get IPs assigned to node grouped by network group. - - :param node: Node instance - :returns: dict mapping network group name to IP addresses - """ - return {ng.name: ip for ng, ip in cls.get_networks_ips(instance)} - - @classmethod - def set_networks_ips(cls, instance, ips_by_network_name): - """Set IPs by provided network-to-IP mapping. - - :param instance: Node instance - :param ips_by_network_name: dict - :returns: None - """ - ngs = db().query( - models.NetworkGroup.name, models.IPAddr - ).filter( - models.NetworkGroup.group_id == instance.group_id, - models.IPAddr.network == models.NetworkGroup.id, - models.IPAddr.node == instance.id, - models.NetworkGroup.name.in_(ips_by_network_name) - ) - for ng_name, ip_addr in ngs: - ip_addr.ip_addr = ips_by_network_name[ng_name] - db().flush() - @classmethod def set_netgroups_ids(cls, instance, netgroups_id_mapping): """Set IP network group assignment based on provided mapping. @@ -178,38 +122,6 @@ class Node(NailgunObject): bond_assignment.network_id = \ netgroups_id_mapping[bond_assignment.network_id] - @classmethod - def get_interface_by_net_name(cls, instance_id, netname): - """Get interface with specified network assigned to it. - - This method first checks for a NodeNICInterface with the specified - network assigned. If that fails it will look for a NodeBondInterface - with that network assigned. - - :param instance_id: Node ID - :param netname: NetworkGroup name - :returns: either NodeNICInterface or NodeBondInterface - """ - iface = db().query(models.NodeNICInterface).join( - (models.NetworkGroup, - models.NodeNICInterface.assigned_networks_list) - ).filter( - models.NetworkGroup.name == netname - ).filter( - models.NodeNICInterface.node_id == instance_id - ).first() - if iface: - return iface - - return db().query(models.NodeBondInterface).join( - (models.NetworkGroup, - models.NodeBondInterface.assigned_networks_list) - ).filter( - models.NetworkGroup.name == netname - ).filter( - models.NodeBondInterface.node_id == instance_id - ).first() - @classmethod def get_interface_by_mac_or_name(cls, instance, mac=None, name=None): # try to get interface by mac address @@ -223,33 +135,6 @@ class Node(NailgunObject): n for n in instance.nic_interfaces if n.name == name), None) return interface - @classmethod - def get_admin_ip(cls, node, admin_net_id=None): - """Get admin IP for specified node. - - When admin_net_id is None the admin network group for the node's - nodegroup will be used. - - If all_ips is True it will return all IPs from the admin network - assigned to that node. Otherwise it just returns a single IP. - - :param node: return admin IP of this node - :type node: nailgun.db.sqlalchemy.models.Node - :param admin_net_id: Admin NetworkGroup ID - :type admin_net_id: int - :param all_ips: - :type all_ips: boolean - :returns: IPAddr instance - """ - if not admin_net_id: - admin_net = NetworkGroup.get_admin_network_group(node) - admin_net_id = admin_net.id - - admin_ip = next((ip for ip in node.ip_addrs - if ip.network == admin_net_id), None) - - return getattr(admin_ip, 'ip_addr', None) - @classmethod def get_all_node_ips(cls): """Get all Admin IPs assigned to nodes. @@ -375,13 +260,6 @@ class Node(NailgunObject): return False - @classmethod - def assign_public_network(cls, node): - public_net = next(NetworkGroupCollection.filter_by( - node.nodegroup.networks, - name=consts.NETWORKS.public), None) - cls.assign_network_to_interface(node, public_net) - @staticmethod def get_interfaces_without_bonds_slaves(node): ifaces = set(node.interfaces) @@ -389,55 +267,6 @@ class Node(NailgunObject): ifaces ^= set(bond.slaves) return sorted(ifaces, key=operator.attrgetter('name')) - @classmethod - def assign_network_to_interface(cls, node, network): - """Assign network to interface by default for single node - - Assign given network to first available interface. - Checks interface type, if network is already assigned - and already assigned networks. - """ - if network is None: - return - untagged = NetworkGroup.is_untagged(network) - dedicated = network.meta.get('dedicated_nic') - ifaces = cls.get_interfaces_without_bonds_slaves(node) - for iface in ifaces: - if dedicated and iface.assigned_networks_list: - continue - for net in iface.assigned_networks_list: - if net.meta.get('dedicated_nic'): - break - if net == network: - return - if untagged and NetworkGroup.is_untagged(net): - break - else: - assigned_nets = iface.assigned_networks_list + [network] - NIC.assign_networks(iface, assigned_nets) - break - else: - logger.warning( - "Cannot assign network %r appropriately for " - "node %r. Set unassigned network to the " - "interface %r", - network.name, node.name, ifaces[0].name - ) - assigned_nets = ifaces[0].assigned_networks_list + [network] - NIC.assign_networks(ifaces[0], assigned_nets) - - @classmethod - def unassign_public_network(cls, node): - public_net = next(NetworkGroupCollection.filter_by( - node.nodegroup.networks, - name=consts.NETWORKS.public), None) - ifaces = cls.get_interfaces_without_bonds_slaves(node) - for iface in ifaces: - network_list = iface.assigned_networks_list - if public_net in network_list: - network_list.remove(public_net) - NIC.assign_networks(iface, network_list) - @classmethod def create(cls, data): """Create Node instance with specified parameters in DB. @@ -841,7 +670,6 @@ class Node(NailgunObject): # - mac to ip mapping from dnsmasq.conf is deleted # imho we need to revert node to original state, as it was # added to cluster (without any additonal state in database) - IPAddr.delete_by_node(instance.id) fire_callback_on_node_reset(instance) db().flush() @@ -1117,16 +945,13 @@ class Node(NailgunObject): :param instance: Node instance :returns: None """ + fire_callback_on_remove_node_from_cluster(instance) + if instance.cluster: Cluster.clear_pending_changes( instance.cluster, node_id=instance.id ) - netmanager = Cluster.get_network_manager( - instance.cluster - ) - netmanager.clear_assigned_networks(instance) - netmanager.clear_bond_configuration(instance) cls.update_roles(instance, []) cls.update_pending_roles(instance, []) cls.remove_replaced_params(instance) @@ -1280,16 +1105,6 @@ class Node(NailgunObject): hostname = 'node-{0}'.format(node.uuid) return hostname - @classmethod - def get_nic_by_name(cls, instance, iface_name): - nic = db().query(models.NodeNICInterface).filter_by( - name=iface_name - ).filter_by( - node_id=instance.id - ).first() - - return nic - @classmethod def reset_vms_created_state(cls, node): if consts.VIRTUAL_NODE_TYPES.virt not in node.all_roles: diff --git a/nailgun/nailgun/objects/node_group.py b/nailgun/nailgun/objects/node_group.py index ba1759881d..7f30c4b1a9 100644 --- a/nailgun/nailgun/objects/node_group.py +++ b/nailgun/nailgun/objects/node_group.py @@ -20,6 +20,7 @@ from nailgun.objects.serializers.node_group import NodeGroupSerializer from nailgun.db import db from nailgun.db.sqlalchemy import models from nailgun import errors +from nailgun.extensions import fire_callback_on_nodegroup_create from nailgun.objects import Cluster from nailgun.objects import NailgunCollection from nailgun.objects import NailgunObject @@ -33,25 +34,11 @@ class NodeGroup(NailgunObject): @classmethod def create(cls, data): new_group = super(NodeGroup, cls).create(data) + cluster = Cluster.get_by_uid(new_group.cluster_id) try: - cluster = Cluster.get_by_uid(new_group.cluster_id) - nm = Cluster.get_network_manager(cluster) - nst = cluster.network_config.segmentation_type - # We have two node groups here when user adds the first custom - # node group. - if NodeGroupCollection.get_by_cluster_id(cluster.id).count() == 2: - nm.ensure_gateways_present_in_default_node_group(cluster) - nm.create_network_groups( - cluster, neutron_segment_type=nst, node_group_id=new_group.id, - set_all_gateways=True) - nm.create_admin_network_group(new_group.cluster_id, new_group.id) - except ( - errors.OutOfVLANs, - errors.OutOfIPs, - errors.NoSuitableCIDR - ) as exc: + fire_callback_on_nodegroup_create(new_group) + except errors.CannotCreate: db().delete(new_group) - raise errors.CannotCreate(exc.message) db().flush() db().refresh(cluster) diff --git a/nailgun/nailgun/orchestrator/deployment_serializers.py b/nailgun/nailgun/orchestrator/deployment_serializers.py index 8247e246c2..fdb4481e47 100644 --- a/nailgun/nailgun/orchestrator/deployment_serializers.py +++ b/nailgun/nailgun/orchestrator/deployment_serializers.py @@ -22,6 +22,7 @@ from distutils.version import StrictVersion import six from nailgun import consts +from nailgun.extensions import fire_callback_on_before_deployment_serialization from nailgun.extensions import fire_callback_on_deployment_data_serialization from nailgun.logger import logger from nailgun import objects @@ -836,9 +837,11 @@ def _execute_pipeline(data, cluster, nodes, ignore_customized): def _invoke_serializer(serializer, cluster, nodes, ignore_customized): + fire_callback_on_before_deployment_serialization( + cluster, cluster.nodes, ignore_customized + ) + objects.Cluster.set_primary_roles(cluster, nodes) - # TODO(apply only for specified subset of nodes) - objects.Cluster.prepare_for_deployment(cluster, cluster.nodes) data = serializer.serialize( cluster, nodes, ignore_customized=ignore_customized ) diff --git a/nailgun/nailgun/orchestrator/neutron_serializers.py b/nailgun/nailgun/orchestrator/neutron_serializers.py index e634fb3dc8..cfc1dad7e6 100644 --- a/nailgun/nailgun/orchestrator/neutron_serializers.py +++ b/nailgun/nailgun/orchestrator/neutron_serializers.py @@ -253,7 +253,7 @@ class NeutronNetworkDeploymentSerializer( attrs['transformations'].append({ 'action': 'add-patch', 'bridges': [ - 'br-%s' % objects.Node.get_interface_by_net_name( + 'br-%s' % objects.NIC.get_interface_by_net_name( node.id, 'private' ).name, diff --git a/nailgun/nailgun/orchestrator/provisioning_serializers.py b/nailgun/nailgun/orchestrator/provisioning_serializers.py index 6ebd47f5dd..f1bc108eea 100644 --- a/nailgun/nailgun/orchestrator/provisioning_serializers.py +++ b/nailgun/nailgun/orchestrator/provisioning_serializers.py @@ -22,6 +22,8 @@ import netaddr import six from nailgun import consts +from nailgun.extensions import \ + fire_callback_on_before_provisioning_serialization from nailgun.extensions import fire_callback_on_provisioning_data_serialization from nailgun.logger import logger from nailgun import objects @@ -381,7 +383,9 @@ def _execute_pipeline(data, cluster, nodes, ignore_customized): def serialize(cluster, nodes, ignore_customized=False): """Serialize cluster for provisioning.""" - objects.Cluster.prepare_for_provisioning(cluster, nodes) + fire_callback_on_before_provisioning_serialization( + cluster, nodes, ignore_customized + ) serializer = get_serializer_for_cluster(cluster) data = serializer.serialize( diff --git a/nailgun/nailgun/test/unit/test_objects.py b/nailgun/nailgun/test/unit/test_objects.py index 2d2c2d0f04..4a0e2e174a 100644 --- a/nailgun/nailgun/test/unit/test_objects.py +++ b/nailgun/nailgun/test/unit/test_objects.py @@ -42,7 +42,6 @@ from nailgun import errors from nailgun import consts from nailgun import plugins -from nailgun.db.sqlalchemy.models import NodeBondInterface from nailgun.db.sqlalchemy.models import NodeGroup from nailgun.db.sqlalchemy.models import Task @@ -1313,26 +1312,6 @@ class TestClusterObject(BaseTestCase): self.cluster, ['controller', 'cinder']) - def test_get_nic_interfaces_for_all_nodes(self): - nodes = self.env.nodes - interfaces = [] - for node in nodes: - for inf in node.nic_interfaces: - interfaces.append(inf) - nic_interfaces = objects.Cluster.get_nic_interfaces_for_all_nodes( - self.cluster) - self.assertEqual(len(nic_interfaces), len(interfaces)) - - def test_get_bond_interfaces_for_all_nodes(self): - node = self.env.nodes[0] - node.bond_interfaces.append( - NodeBondInterface(name='ovs-bond0', - slaves=node.nic_interfaces)) - self.db.flush() - bond_interfaces = objects.Cluster.get_bond_interfaces_for_all_nodes( - self.cluster) - self.assertEqual(len(bond_interfaces), 1) - def test_get_network_roles(self): self.assertItemsEqual( objects.Cluster.get_network_roles(self.cluster),