# -*- coding: utf-8 -*- # Copyright 2013 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import json from mock import patch from sqlalchemy.sql import not_ from nailgun.db.sqlalchemy.models import Cluster from nailgun.db.sqlalchemy.models import NetworkGroup from nailgun.network.manager import NetworkManager from nailgun.test.base import BaseIntegrationTest from nailgun.test.base import reverse class TestNovaNetworkConfigurationHandlerMultinode(BaseIntegrationTest): def setUp(self): super(TestNovaNetworkConfigurationHandlerMultinode, self).setUp() cluster = self.env.create_cluster(api=True) self.cluster = self.db.query(Cluster).get(cluster['id']) def test_get_request_should_return_net_manager_and_networks(self): response = self.env.nova_networks_get(self.cluster.id) data = json.loads(response.body) cluster = self.db.query(Cluster).get(self.cluster.id) self.assertEquals(data['net_manager'], self.cluster.net_manager) for network_group in cluster.network_groups: network = [i for i in data['networks'] if i['id'] == network_group.id][0] keys = [ 'network_size', 'name', 'amount', 'cluster_id', 'vlan_start', 'cidr', 'id'] for key in keys: self.assertEquals(network[key], getattr(network_group, key)) def test_not_found_cluster(self): resp = self.env.nova_networks_get(self.cluster.id + 999, expect_errors=True) self.assertEquals(404, resp.status_code) def test_change_net_manager(self): new_net_manager = {'net_manager': 'VlanManager'} self.env.nova_networks_put(self.cluster.id, new_net_manager) self.db.refresh(self.cluster) self.assertEquals( self.cluster.net_manager, new_net_manager['net_manager']) def test_change_dns_nameservers(self): new_dns_nameservers = { 'dns_nameservers': { "nameservers": [ "208.67.222.222", "208.67.220.220" ] } } self.env.nova_networks_put(self.cluster.id, new_dns_nameservers) self.db.refresh(self.cluster) self.assertEquals( self.cluster.dns_nameservers, new_dns_nameservers['dns_nameservers']['nameservers'] ) def test_refresh_mask_on_cidr_change(self): response = self.env.nova_networks_get(self.cluster.id) data = json.loads(response.body) mgmt = [n for n in data['networks'] if n['name'] == 'management'][0] cidr = mgmt['cidr'].partition('/')[0] + '/25' mgmt['cidr'] = cidr mgmt['network_size'] = 128 resp = self.env.nova_networks_put(self.cluster.id, data) self.assertEquals(resp.status_code, 202) task = json.loads(resp.body) self.assertEquals(task['status'], 'ready') self.db.refresh(self.cluster) mgmt_ng = [ng for ng in self.cluster.network_groups if ng.name == 'management'][0] self.assertEquals(mgmt_ng.cidr, cidr) self.assertEquals(mgmt_ng.netmask, '255.255.255.128') def test_wrong_net_provider(self): resp = self.app.put( reverse( 'NeutronNetworkConfigurationHandler', kwargs={'cluster_id': self.cluster.id}), json.dumps({}), headers=self.default_headers, expect_errors=True ) self.assertEquals(resp.status_code, 400) self.assertEquals( resp.body, u"Wrong net provider - environment uses 'nova_network'" ) def test_do_not_update_net_manager_if_validation_is_failed(self): new_net_manager = {'net_manager': 'VlanManager', 'networks': [{'id': 500, 'vlan_start': 500}]} self.env.nova_networks_put(self.cluster.id, new_net_manager, expect_errors=True) self.db.refresh(self.cluster) self.assertNotEquals( self.cluster.net_manager, new_net_manager['net_manager']) def test_network_group_update_changes_network(self): network = self.db.query(NetworkGroup).filter( not_(NetworkGroup.name == "fuelweb_admin") ).first() self.assertIsNotNone(network) new_vlan_id = 500 # non-used vlan id new_nets = {'networks': [{'id': network.id, 'vlan_start': new_vlan_id}]} resp = self.env.nova_networks_put(self.cluster.id, new_nets) self.assertEquals(resp.status_code, 202) self.db.refresh(network) self.assertEquals(network.amount, 1) self.assertEquals(network.vlan_start, 500) def test_update_networks_and_net_manager(self): network = self.db.query(NetworkGroup).filter( not_(NetworkGroup.name == "fuelweb_admin") ).first() new_vlan_id = 500 # non-used vlan id new_net = {'net_manager': 'VlanManager', 'networks': [{'id': network.id, 'vlan_start': new_vlan_id}]} self.env.nova_networks_put(self.cluster.id, new_net) self.db.refresh(self.cluster) self.db.refresh(network) self.assertEquals( self.cluster.net_manager, new_net['net_manager']) self.assertEquals(network.vlan_start, new_vlan_id) def test_networks_update_fails_with_wrong_net_id(self): new_nets = {'networks': [{'id': 500, 'vlan_start': 500}]} resp = self.env.nova_networks_put(self.cluster.id, new_nets, expect_errors=True) self.assertEquals(202, resp.status_code) task = json.loads(resp.body) self.assertEquals(task['status'], 'error') self.assertEquals( task['message'], 'Invalid network ID: 500' ) def test_admin_public_floating_untagged_others_tagged(self): resp = self.env.nova_networks_get(self.cluster.id) data = json.loads(resp.body) for net in data['networks']: if net['name'] in ('fuelweb_admin', 'public', 'floating'): self.assertIsNone(net['vlan_start']) else: self.assertIsNotNone(net['vlan_start']) def test_mgmt_storage_networks_have_no_gateway(self): resp = self.env.nova_networks_get(self.cluster.id) self.assertEquals(200, resp.status_code) data = json.loads(resp.body) for net in data['networks']: if net['name'] in ['management', 'storage']: self.assertIsNone(net['gateway']) def test_management_network_has_gw(self): net_meta = self.env.get_default_networks_metadata().copy() mgmt = filter(lambda n: n['name'] == 'management', net_meta['nova_network']['networks'])[0] mgmt['use_gateway'] = True mgmt['gateway'] = '192.168.0.1' def get_new_networks_metadata(): return net_meta self.env.get_default_networks_metadata = get_new_networks_metadata cluster = self.env.create( cluster_kwargs={}, nodes_kwargs=[{"pending_addition": True}] ) resp = self.env.nova_networks_get(cluster['id']) data = json.loads(resp.body) mgmt = filter(lambda n: n['name'] == 'management', data['networks'])[0] self.assertEquals(mgmt['gateway'], '192.168.0.1') strg = filter(lambda n: n['name'] == 'storage', data['networks'])[0] self.assertIsNone(strg['gateway']) def test_management_network_gw_set_but_not_in_use(self): net_meta = self.env.get_default_networks_metadata().copy() mgmt = filter(lambda n: n['name'] == 'management', net_meta['nova_network']['networks'])[0] mgmt['gateway'] = '192.168.0.1' self.assertEquals(mgmt['use_gateway'], False) def get_new_networks_metadata(): return net_meta self.env.get_default_networks_metadata = get_new_networks_metadata cluster = self.env.create( cluster_kwargs={}, nodes_kwargs=[{"pending_addition": True}] ) resp = self.env.nova_networks_get(cluster['id']) data = json.loads(resp.body) for n in data['networks']: if n['name'] in ('management', 'storage'): self.assertIsNone(n['gateway']) class TestNeutronNetworkConfigurationHandlerMultinode(BaseIntegrationTest): def setUp(self): super(TestNeutronNetworkConfigurationHandlerMultinode, self).setUp() cluster = self.env.create_cluster(api=True, net_provider='neutron', net_segment_type='gre', mode='ha_compact' ) self.cluster = self.db.query(Cluster).get(cluster['id']) def test_get_request_should_return_net_provider_segment_and_networks(self): response = self.env.neutron_networks_get(self.cluster.id) data = json.loads(response.body) cluster = self.db.query(Cluster).get(self.cluster.id) self.assertEquals(data['net_provider'], self.cluster.net_provider) self.assertEquals(data['net_segment_type'], self.cluster.net_segment_type) for network_group in cluster.network_groups: network = [i for i in data['networks'] if i['id'] == network_group.id][0] keys = [ 'network_size', 'name', 'amount', 'cluster_id', 'vlan_start', 'cidr', 'id'] for key in keys: self.assertEquals(network[key], getattr(network_group, key)) def test_get_request_should_return_vips(self): response = self.env.neutron_networks_get(self.cluster.id) data = json.loads(response.body) self.assertIn('public_vip', data) self.assertIn('management_vip', data) def test_not_found_cluster(self): resp = self.env.neutron_networks_get(self.cluster.id + 999, expect_errors=True) self.assertEquals(404, resp.status_code) def test_refresh_mask_on_cidr_change(self): response = self.env.neutron_networks_get(self.cluster.id) data = json.loads(response.body) mgmt = [n for n in data['networks'] if n['name'] == 'management'][0] cidr = mgmt['cidr'].partition('/')[0] + '/25' mgmt['cidr'] = cidr mgmt['network_size'] = 128 resp = self.env.neutron_networks_put(self.cluster.id, data) self.assertEquals(202, resp.status_code) task = json.loads(resp.body) self.assertEquals(task['status'], 'ready') self.db.refresh(self.cluster) mgmt_ng = [ng for ng in self.cluster.network_groups if ng.name == 'management'][0] self.assertEquals(mgmt_ng.cidr, cidr) self.assertEquals(mgmt_ng.netmask, '255.255.255.128') def test_do_not_update_net_segmentation_type(self): resp = self.env.neutron_networks_get(self.cluster.id) data = json.loads(resp.body) data['neutron_parameters']['segmentation_type'] = 'vlan' resp = self.env.neutron_networks_put(self.cluster.id, data, expect_errors=True) self.assertEquals(202, resp.status_code) task = json.loads(resp.body) self.assertEquals(task['status'], 'error') self.assertEquals( task['message'], "Change of 'segmentation_type' is prohibited" ) def test_network_group_update_changes_network(self): resp = self.env.neutron_networks_get(self.cluster.id) data = json.loads(resp.body) network = self.db.query(NetworkGroup).get(data['networks'][0]['id']) self.assertIsNotNone(network) data['networks'][0]['vlan_start'] = 500 # non-used vlan id resp = self.env.neutron_networks_put(self.cluster.id, data) self.assertEquals(resp.status_code, 202) self.db.refresh(network) self.assertEquals(network.amount, 1) self.assertEquals(network.vlan_start, 500) def test_update_networks_fails_if_change_net_segmentation_type(self): resp = self.env.neutron_networks_get(self.cluster.id) data = json.loads(resp.body) network = self.db.query(NetworkGroup).get(data['networks'][0]['id']) self.assertIsNotNone(network) data['networks'][0]['vlan_start'] = 500 # non-used vlan id data['neutron_parameters']['segmentation_type'] = 'vlan' resp = self.env.neutron_networks_put(self.cluster.id, data, expect_errors=True) self.assertEquals(202, resp.status_code) task = json.loads(resp.body) self.assertEquals(task['status'], 'error') self.assertEquals( task['message'], "Change of 'segmentation_type' is prohibited" ) def test_networks_update_fails_with_wrong_net_id(self): new_nets = {'networks': [{'id': 500, 'name': 'new', 'vlan_start': 500}]} resp = self.env.neutron_networks_put(self.cluster.id, new_nets, expect_errors=True) self.assertEquals(202, resp.status_code) task = json.loads(resp.body) self.assertEquals(task['status'], 'error') self.assertEquals( task['message'], 'Invalid network ID: 500' ) def test_refresh_public_cidr_on_range_gw_change(self): data = json.loads(self.env.neutron_networks_get(self.cluster.id).body) publ = filter(lambda ng: ng['name'] == 'public', data['networks'])[0] self.assertEquals(publ['cidr'], '172.16.0.0/24') publ['gateway'] = '199.61.0.1' publ['ip_ranges'] = [['199.61.0.11', '199.61.0.33'], ['199.61.0.55', '199.61.0.99']] virt_nets = data['neutron_parameters']['predefined_networks'] virt_nets['net04_ext']['L3']['floating'] = ['199.61.0.111', '199.61.0.122'] resp = self.env.neutron_networks_put(self.cluster.id, data) self.assertEquals(202, resp.status_code) task = json.loads(resp.body) self.assertEquals(task['status'], 'ready') self.db.refresh(self.cluster) publ_ng = filter(lambda ng: ng.name == 'public', self.cluster.network_groups)[0] self.assertEquals(publ_ng.cidr, '199.61.0.0/24') def test_refresh_public_cidr_on_netmask_change(self): data = json.loads(self.env.neutron_networks_get(self.cluster.id).body) publ = filter(lambda ng: ng['name'] == 'public', data['networks'])[0] self.assertEquals(publ['cidr'], '172.16.0.0/24') publ['netmask'] = '255.255.252.0' resp = self.env.neutron_networks_put(self.cluster.id, data) self.assertEquals(202, resp.status_code) task = json.loads(resp.body) self.assertEquals(task['status'], 'ready') self.db.refresh(self.cluster) publ_ng = filter(lambda ng: ng.name == 'public', self.cluster.network_groups)[0] self.assertEquals(publ_ng.cidr, '172.16.0.0/22') def test_do_not_refresh_public_cidr_on_its_change(self): data = json.loads(self.env.neutron_networks_get(self.cluster.id).body) publ = filter(lambda ng: ng['name'] == 'public', data['networks'])[0] self.assertEquals(publ['cidr'], '172.16.0.0/24') publ['cidr'] = '199.61.39.160/28' # it is OK as public CIDR is ignored and nothing else is changed resp = self.env.neutron_networks_put(self.cluster.id, data) self.assertEquals(202, resp.status_code) task = json.loads(resp.body) self.assertEquals(task['status'], 'ready') self.db.refresh(self.cluster) publ_ng = filter(lambda ng: ng.name == 'public', self.cluster.network_groups)[0] self.assertEquals(publ_ng.cidr, '172.16.0.0/24') def test_admin_public_untagged_others_tagged(self): resp = self.env.neutron_networks_get(self.cluster.id) data = json.loads(resp.body) for net in data['networks']: if net['name'] in ('fuelweb_admin', 'public',): self.assertIsNone(net['vlan_start']) else: self.assertIsNotNone(net['vlan_start']) def test_mgmt_storage_networks_have_no_gateway(self): resp = self.env.neutron_networks_get(self.cluster.id) self.assertEquals(200, resp.status_code) data = json.loads(resp.body) for net in data['networks']: if net['name'] in ['management', 'storage']: self.assertIsNone(net['gateway']) def test_management_network_has_gw(self): net_meta = self.env.get_default_networks_metadata().copy() mgmt = filter(lambda n: n['name'] == 'management', net_meta['neutron']['networks'])[0] mgmt['use_gateway'] = True def get_new_networks_metadata(): return net_meta self.env.get_default_networks_metadata = get_new_networks_metadata cluster = self.env.create( cluster_kwargs={'net_provider': 'neutron', 'net_segment_type': 'gre'}, nodes_kwargs=[{"pending_addition": True}] ) resp = self.env.neutron_networks_get(cluster['id']) data = json.loads(resp.body) mgmt = filter(lambda n: n['name'] == 'management', data['networks'])[0] self.assertEquals(mgmt['gateway'], '192.168.0.1') strg = filter(lambda n: n['name'] == 'storage', data['networks'])[0] self.assertIsNone(strg['gateway']) class TestNovaNetworkConfigurationHandlerHA(BaseIntegrationTest): def setUp(self): super(TestNovaNetworkConfigurationHandlerHA, self).setUp() cluster = self.env.create_cluster(api=True, mode='ha_compact') self.cluster = self.db.query(Cluster).get(cluster['id']) self.net_manager = NetworkManager def test_returns_management_vip_and_public_vip(self): resp = json.loads(self.env.nova_networks_get(self.cluster.id).body) self.assertEquals( resp['management_vip'], self.net_manager.assign_vip(self.cluster.id, 'management')) self.assertEquals( resp['public_vip'], self.net_manager.assign_vip(self.cluster.id, 'public')) class TestAdminNetworkConfiguration(BaseIntegrationTest): @patch('nailgun.db.sqlalchemy.fixman.settings.ADMIN_NETWORK', { "cidr": "192.168.0.0/24", "netmask": "255.255.255.0", "size": "256", "first": "192.168.0.129", "last": "192.168.0.254" }) def setUp(self): super(TestAdminNetworkConfiguration, self).setUp() self.cluster = self.env.create( cluster_kwargs={ "api": True }, nodes_kwargs=[ {"pending_addition": True, "api": True} ] ) def test_netconfig_error_when_admin_cidr_match_other_network_cidr(self): resp = self.env.nova_networks_get(self.cluster['id']) nets = json.loads(resp.body) resp = self.env.nova_networks_put(self.cluster['id'], nets, expect_errors=True) self.assertEquals(resp.status_code, 202) task = json.loads(resp.body) self.assertEquals(task['status'], 'error') self.assertEquals(task['progress'], 100) self.assertEquals(task['name'], 'check_networks') self.assertIn("Address space intersection between networks:\n" "admin (PXE), management.", task['message']) def test_deploy_error_when_admin_cidr_match_other_network_cidr(self): resp = self.env.cluster_changes_put(self.cluster['id'], expect_errors=True) self.assertEquals(resp.status_code, 202) task = json.loads(resp.body) self.assertEquals(task['status'], 'error') self.assertEquals(task['progress'], 100) self.assertEquals(task['name'], 'deploy') self.assertIn("Address space intersection between networks:\n" "admin (PXE), management.", task['message'])