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
This commit is contained in:
parent
c8a3c24ebe
commit
76a0bc226e
|
@ -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 \
|
||||
|
|
|
@ -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"""
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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]):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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.networks)
|
||||
cls.add_pending_changes(
|
||||
cluster, consts.CLUSTER_CHANGES.vmware_attributes)
|
||||
|
||||
if assign_nodes:
|
||||
cls.update_nodes(cluster, assign_nodes)
|
||||
|
||||
ClusterPlugins.add_compatible_plugins(cluster)
|
||||
PluginManager.enable_plugins_by_components(cluster)
|
||||
|
||||
net_manager.assign_vips_for_net_groups(cluster)
|
||||
fire_callback_on_cluster_create(cluster, data)
|
||||
|
||||
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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
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:
|
||||
try:
|
||||
fire_callback_on_nodegroup_create(new_group)
|
||||
except errors.CannotCreate:
|
||||
db().delete(new_group)
|
||||
raise errors.CannotCreate(exc.message)
|
||||
|
||||
db().flush()
|
||||
db().refresh(cluster)
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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),
|
||||
|
|
Loading…
Reference in New Issue