diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/address.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/address.py index 635d4ad256..59e5d628cd 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/address.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/address.py @@ -15,9 +15,10 @@ # License for the specific language governing permissions and limitations # under the License. # -# Copyright (c) 2015 Wind River Systems, Inc. +# Copyright (c) 2015-2022 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 # - import netaddr import pecan @@ -46,7 +47,8 @@ ALLOWED_NETWORK_TYPES = [constants.NETWORK_TYPE_MGMT, constants.NETWORK_TYPE_CLUSTER_HOST, constants.NETWORK_TYPE_DATA, constants.NETWORK_TYPE_IRONIC, - constants.NETWORK_TYPE_STORAGE] + constants.NETWORK_TYPE_STORAGE, + constants.NETWORK_TYPE_ADMIN] class Address(base.APIBase): diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/interface.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/interface.py index d6f3ae7720..ba9f608d9b 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/interface.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/interface.py @@ -16,7 +16,7 @@ # License for the specific language governing permissions and limitations # under the License. # -# Copyright (c) 2013-2021 Wind River Systems, Inc. +# Copyright (c) 2013-2022 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -70,7 +70,8 @@ VALID_NETWORK_TYPES = [constants.NETWORK_TYPE_NONE, constants.NETWORK_TYPE_PCI_PASSTHROUGH, constants.NETWORK_TYPE_PCI_SRIOV, constants.NETWORK_TYPE_IRONIC, - constants.NETWORK_TYPE_STORAGE] + constants.NETWORK_TYPE_STORAGE, + constants.NETWORK_TYPE_ADMIN] VALID_INTERFACE_CLASS = [constants.INTERFACE_CLASS_PLATFORM, constants.INTERFACE_CLASS_DATA, diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/interface_network.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/interface_network.py index e13679e958..aaec2f3dd8 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/interface_network.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/interface_network.py @@ -16,7 +16,9 @@ # License for the specific language governing permissions and limitations # under the License. # -# Copyright (c) 2013-2021 Wind River Systems, Inc. +# Copyright (c) 2013-2022 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 # import os @@ -52,7 +54,8 @@ NONDUPLICATE_NETWORK_TYPES = (constants.NETWORK_TYPE_MGMT, constants.NETWORK_TYPE_OAM, constants.NETWORK_TYPE_CLUSTER_HOST, constants.NETWORK_TYPE_PXEBOOT, - constants.NETWORK_TYPE_STORAGE) + constants.NETWORK_TYPE_STORAGE, + constants.NETWORK_TYPE_ADMIN) class InterfaceNetwork(base.APIBase): @@ -413,6 +416,8 @@ class InterfaceNetworkController(rest.RestController): def _update_host_address(host, interface, network_type): if network_type == constants.NETWORK_TYPE_MGMT: _update_host_mgmt_address(host, interface) + elif network_type == constants.NETWORK_TYPE_ADMIN: + _update_host_admin_address(host, interface) elif network_type == constants.NETWORK_TYPE_CLUSTER_HOST: _update_host_cluster_address(host, interface) elif network_type == constants.NETWORK_TYPE_IRONIC: @@ -458,6 +463,23 @@ def _update_host_mgmt_address(host, interface): _allocate_pool_address(interface['id'], mgmt_pool_uuid, address_name) +def _update_host_admin_address(host, interface): + address_name = cutils.format_address_name(host.hostname, + constants.NETWORK_TYPE_ADMIN) + try: + address = pecan.request.dbapi.address_get_by_name(address_name) + updates = {'interface_id': interface['id']} + pecan.request.dbapi.address_update(address.uuid, updates) + except exception.AddressNotFoundByName: + # For non-controller hosts, allocate address from pool if dynamic + admin_network = pecan.request.dbapi.network_get_by_type( + constants.NETWORK_TYPE_ADMIN) + if admin_network.dynamic: + _allocate_pool_address(interface['id'], + admin_network.pool_uuid, + address_name) + + def _update_host_oam_address(host, interface): if utils.get_system_mode() == constants.SYSTEM_MODE_SIMPLEX: address_name = cutils.format_address_name(constants.CONTROLLER_HOSTNAME, diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/network.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/network.py index af5348cb4c..0758931ed3 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/network.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/network.py @@ -15,7 +15,9 @@ # License for the specific language governing permissions and limitations # under the License. # -# Copyright (c) 2015 Wind River Systems, Inc. +# Copyright (c) 2015-2022 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 # import collections @@ -52,7 +54,7 @@ ALLOWED_NETWORK_TYPES = [constants.NETWORK_TYPE_MGMT, constants.NETWORK_TYPE_IRONIC, constants.NETWORK_TYPE_SYSTEM_CONTROLLER_OAM, constants.NETWORK_TYPE_STORAGE, - ] + constants.NETWORK_TYPE_ADMIN] class Network(base.APIBase): @@ -173,6 +175,8 @@ class NetworkController(rest.RestController): def _create_network_addresses(self, pool, network): if network['type'] == constants.NETWORK_TYPE_MGMT: addresses = self._create_mgmt_network_address(pool) + elif network['type'] == constants.NETWORK_TYPE_ADMIN: + addresses = self._create_admin_network_address() elif network['type'] == constants.NETWORK_TYPE_PXEBOOT: addresses = self._create_pxeboot_network_address() elif network['type'] == constants.NETWORK_TYPE_CLUSTER_HOST: @@ -209,6 +213,13 @@ class NetworkController(rest.RestController): pool.gateway_address return addresses + def _create_admin_network_address(self): + addresses = collections.OrderedDict() + addresses[constants.CONTROLLER_HOSTNAME] = None + addresses[constants.CONTROLLER_0_HOSTNAME] = None + addresses[constants.CONTROLLER_1_HOSTNAME] = None + return addresses + def _create_pxeboot_network_address(self): addresses = collections.OrderedDict() addresses[constants.CONTROLLER_HOSTNAME] = None @@ -395,7 +406,8 @@ class NetworkController(rest.RestController): constants.NETWORK_TYPE_PXEBOOT, constants.NETWORK_TYPE_CLUSTER_POD, constants.NETWORK_TYPE_CLUSTER_SERVICE, - constants.NETWORK_TYPE_STORAGE]: + constants.NETWORK_TYPE_STORAGE, + constants.NETWORK_TYPE_ADMIN]: msg = _("Cannot delete type {} network {} after initial " "configuration completion" .format(network['type'], network_uuid)) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/route.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/route.py index 60e0b6c730..95809bba02 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/route.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/route.py @@ -17,6 +17,8 @@ # # Copyright (c) 2015-2022 Wind River Systems, Inc. # +# SPDX-License-Identifier: Apache-2.0 +# import netaddr import pecan @@ -46,7 +48,8 @@ ALLOWED_NETWORK_TYPES = [constants.NETWORK_TYPE_DATA, constants.NETWORK_TYPE_MGMT, constants.NETWORK_TYPE_CLUSTER_HOST, constants.NETWORK_TYPE_STORAGE, - constants.NETWORK_TYPE_OAM] + constants.NETWORK_TYPE_OAM, + constants.NETWORK_TYPE_ADMIN] class Route(base.APIBase): diff --git a/sysinv/sysinv/sysinv/sysinv/common/constants.py b/sysinv/sysinv/sysinv/sysinv/common/constants.py index 67afc6fe8a..bf650182ee 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/constants.py +++ b/sysinv/sysinv/sysinv/sysinv/common/constants.py @@ -709,6 +709,7 @@ CONTROLLER_AUDIT_REQUESTS = [DISK_AUDIT_REQUEST, # Interface definitions NETWORK_TYPE_NONE = 'none' NETWORK_TYPE_MGMT = 'mgmt' +NETWORK_TYPE_ADMIN = 'admin' NETWORK_TYPE_OAM = 'oam' NETWORK_TYPE_BM = 'bm' NETWORK_TYPE_MULTICAST = 'multicast' @@ -730,7 +731,8 @@ PLATFORM_NETWORK_TYPES = [NETWORK_TYPE_PXEBOOT, NETWORK_TYPE_OAM, NETWORK_TYPE_CLUSTER_HOST, NETWORK_TYPE_IRONIC, - NETWORK_TYPE_STORAGE] + NETWORK_TYPE_STORAGE, + NETWORK_TYPE_ADMIN] PCI_NETWORK_TYPES = [NETWORK_TYPE_PCI_PASSTHROUGH, NETWORK_TYPE_PCI_SRIOV] diff --git a/sysinv/sysinv/sysinv/sysinv/puppet/interface.py b/sysinv/sysinv/sysinv/sysinv/puppet/interface.py index a925b98151..91f5884940 100644 --- a/sysinv/sysinv/sysinv/sysinv/puppet/interface.py +++ b/sysinv/sysinv/sysinv/sysinv/puppet/interface.py @@ -31,7 +31,8 @@ PLATFORM_NETWORK_TYPES = [constants.NETWORK_TYPE_PXEBOOT, constants.NETWORK_TYPE_CLUSTER_HOST, constants.NETWORK_TYPE_OAM, constants.NETWORK_TYPE_IRONIC, - constants.NETWORK_TYPE_STORAGE] + constants.NETWORK_TYPE_STORAGE, + constants.NETWORK_TYPE_ADMIN] DATA_NETWORK_TYPES = [constants.NETWORK_TYPE_DATA] @@ -315,6 +316,19 @@ class InterfacePuppet(base.BasePuppet): except exception.AddressNotFoundByName: pass + try: + admin_address = self._get_address_by_name( + constants.CONTROLLER_HOSTNAME, constants.NETWORK_TYPE_ADMIN) + + admin_floating_ip = (str(admin_address.address) + '/' + + str(admin_address.prefix)) + + floating_ips.update({ + constants.NETWORK_TYPE_ADMIN: admin_floating_ip, + }) + except exception.AddressNotFoundByName: + pass + return floating_ips def _get_datanetworks(self, host): @@ -724,6 +738,8 @@ def get_interface_address_method(context, iface, network_id=None): return STATIC_METHOD elif networktype == constants.NETWORK_TYPE_STORAGE: return STATIC_METHOD + elif networktype == constants.NETWORK_TYPE_ADMIN: + return STATIC_METHOD elif networktype == constants.NETWORK_TYPE_PXEBOOT: # All pxeboot interfaces that exist on non-controller nodes are set # to manual as they are not needed/used once the install is done. diff --git a/sysinv/sysinv/sysinv/sysinv/puppet/networking.py b/sysinv/sysinv/sysinv/sysinv/puppet/networking.py index 8500f7eb2e..6691a992b5 100644 --- a/sysinv/sysinv/sysinv/sysinv/puppet/networking.py +++ b/sysinv/sysinv/sysinv/sysinv/puppet/networking.py @@ -24,6 +24,7 @@ class NetworkingPuppet(base.BasePuppet): config.update(self._get_oam_network_config()) config.update(self._get_cluster_network_config()) config.update(self._get_ironic_network_config()) + config.update(self._get_admin_network_config()) config.update(self._get_storage_network_config()) return config @@ -34,6 +35,7 @@ class NetworkingPuppet(base.BasePuppet): config.update(self._get_cluster_interface_config()) config.update(self._get_ironic_interface_config()) config.update(self._get_storage_interface_config()) + config.update(self._get_admin_interface_config()) config.update(self._get_instance_ptp_config(host)) if host.personality == constants.CONTROLLER: config.update(self._get_oam_interface_config()) @@ -93,6 +95,11 @@ class NetworkingPuppet(base.BasePuppet): config = self._get_network_config(networktype) return config + def _get_admin_network_config(self): + networktype = constants.NETWORK_TYPE_ADMIN + config = self._get_network_config(networktype) + return config + def _get_network_config(self, networktype): try: network = self.dbapi.network_get_by_type(networktype) @@ -181,6 +188,9 @@ class NetworkingPuppet(base.BasePuppet): def _get_storage_interface_config(self): return self._get_interface_config(constants.NETWORK_TYPE_STORAGE) + def _get_admin_interface_config(self): + return self._get_interface_config(constants.NETWORK_TYPE_ADMIN) + def _set_ptp_instance_global_parameters(self, ptp_instances, ptp_parameters_instance): default_global_parameters = { diff --git a/sysinv/sysinv/sysinv/sysinv/tests/api/test_network.py b/sysinv/sysinv/sysinv/sysinv/tests/api/test_network.py index 4c1f38cd6d..9dd3dfa58d 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/api/test_network.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/api/test_network.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2020 Wind River Systems, Inc. +# Copyright (c) 2020-2022 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -116,6 +116,10 @@ class NetworkTestCase(base.FunctionalTest, dbbase.BaseHostTestCase): hostnames, self.storage_subnet, constants.NETWORK_TYPE_STORAGE) + self._create_test_addresses( + hostnames, self.admin_subnet, + constants.NETWORK_TYPE_ADMIN) + self._create_test_addresses( hostnames, self.system_controller_subnet, constants.NETWORK_TYPE_SYSTEM_CONTROLLER) @@ -267,6 +271,12 @@ class TestPostMixin(NetworkTestCase): constants.NETWORK_TYPE_STORAGE, self.storage_subnet) + def test_create_success_admin(self): + self._test_create_network_success( + 'admin', + constants.NETWORK_TYPE_ADMIN, + self.admin_subnet) + def test_create_fail_duplicate_pxeboot(self): self._test_create_network_fail_duplicate( 'pxeboot', @@ -309,6 +319,12 @@ class TestPostMixin(NetworkTestCase): constants.NETWORK_TYPE_STORAGE, self.storage_subnet) + def test_create_fail_duplicate_admin(self): + self._test_create_network_fail_duplicate( + 'admin', + constants.NETWORK_TYPE_ADMIN, + self.admin_subnet) + def test_create_with_invalid_type(self): # Test creation with an invalid type address_pool_id = self._create_test_address_pool( @@ -456,6 +472,13 @@ class TestDelete(NetworkTestCase): constants.NETWORK_TYPE_STORAGE ) + def test_delete_admin_subnet(self): + self._test_delete_allowed(constants.NETWORK_TYPE_ADMIN) + + def test_delete_admin_subnet_after_initial_config(self): + self._test_delete_after_initial_config_not_allowed( + constants.NETWORK_TYPE_ADMIN) + def test_delete_data(self): self._test_delete_allowed(constants.NETWORK_TYPE_DATA) diff --git a/sysinv/sysinv/sysinv/sysinv/tests/db/base.py b/sysinv/sysinv/sysinv/sysinv/tests/db/base.py index 8d384bcc1f..e3ec37d033 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/db/base.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/db/base.py @@ -1,3 +1,5 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + # Copyright (c) 2012 NTT DOCOMO, INC. # All Rights Reserved. # @@ -12,6 +14,11 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. +# +# Copyright (c) 2013-2022 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# """Sysinv DB test base class.""" @@ -50,6 +57,7 @@ class BaseIPv4Mixin(object): cluster_service_subnet = netaddr.IPNetwork('10.96.0.0/12') multicast_subnet = netaddr.IPNetwork('239.1.1.0/28') storage_subnet = netaddr.IPNetwork('10.10.20.0/24') + admin_subnet = netaddr.IPNetwork('10.10.30.0/24') system_controller_subnet = netaddr.IPNetwork('192.168.104.0/24') system_controller_oam_subnet = netaddr.IPNetwork('10.10.50.0/24') @@ -69,6 +77,7 @@ class BaseIPv6Mixin(object): cluster_service_subnet = netaddr.IPNetwork('fd04::/112') multicast_subnet = netaddr.IPNetwork('ff08::1:1:0/124') storage_subnet = netaddr.IPNetwork('fd05::/64') + admin_subnet = netaddr.IPNetwork('fd09::/64') system_controller_subnet = netaddr.IPNetwork('fd07::/64') system_controller_oam_subnet = netaddr.IPNetwork('fd06::/64') @@ -265,6 +274,10 @@ class BaseSystemTestCase(BaseIPv4Mixin, DbTestCase): constants.NETWORK_TYPE_STORAGE, self.storage_subnet) + self._create_test_network('admin', + constants.NETWORK_TYPE_ADMIN, + self.admin_subnet) + self._create_test_network('system-controller', constants.NETWORK_TYPE_SYSTEM_CONTROLLER, self.system_controller_subnet) @@ -323,6 +336,10 @@ class BaseSystemTestCase(BaseIPv4Mixin, DbTestCase): hostnames, self.storage_subnet, constants.NETWORK_TYPE_STORAGE) + self._create_test_addresses( + hostnames, self.admin_subnet, + constants.NETWORK_TYPE_ADMIN) + self._create_test_addresses( hostnames, self.system_controller_subnet, constants.NETWORK_TYPE_SYSTEM_CONTROLLER) @@ -444,8 +461,9 @@ class BaseHostTestCase(BaseSystemTestCase): network_types = [constants.NETWORK_TYPE_OAM, constants.NETWORK_TYPE_MGMT, constants.NETWORK_TYPE_CLUSTER_HOST, - constants.NETWORK_TYPE_STORAGE] - ifnames = ['oam', 'mgmt', 'cluster', 'storage'] + constants.NETWORK_TYPE_STORAGE, + constants.NETWORK_TYPE_ADMIN] + ifnames = ['oam', 'mgmt', 'cluster', 'storage', 'admin'] index = 0 ifaces = [] for nt, name in zip(network_types, ifnames):