Add an extract-ports flag
When the extract-ports flag is used, flame extracts the neutron ports and connects them (according to the other flags) to : - floating ips - nova:compute instances - security groups - subnets and networks This allows the exported stack to have the same network configuration as its source. When the flag is used in conjunction with --generate-stack-data, the generated stack data also contains the assocation between ports and floating IPs. Change-Id: Id2e406c7aac5457cdef822b78edf7e30bd833a2d
This commit is contained in:
parent
ab1f11f7bc
commit
1c858ea907
@ -37,6 +37,7 @@ Usage
|
||||
[--os-auth-token OS_AUTH_TOKEN] [--insecure]
|
||||
[--endpoint_type ENDPOINT_TYPE] [--exclude-servers]
|
||||
[--exclude-volumes] [--exclude-keypairs] [--generate-stack-data]
|
||||
[--extract-ports]
|
||||
|
||||
Heat template and data file generator
|
||||
|
||||
@ -62,6 +63,7 @@ Usage
|
||||
--generate-stack-data
|
||||
In addition to template, generate Heat stack data
|
||||
file.
|
||||
--extract-ports Export the tenant network ports
|
||||
|
||||
Usage example
|
||||
-------------
|
||||
|
@ -14,6 +14,7 @@ Contents:
|
||||
readme
|
||||
installation
|
||||
usage
|
||||
limitations
|
||||
contributing
|
||||
|
||||
Indices and tables
|
||||
|
18
doc/source/limitations.rst
Normal file
18
doc/source/limitations.rst
Normal file
@ -0,0 +1,18 @@
|
||||
===========
|
||||
Limitations
|
||||
===========
|
||||
|
||||
Subnets created before Kilo can have their DHCP server's IP in the middle of
|
||||
an allocation pool. This causes the first VMs to be allocated the first
|
||||
free IP addresses of a pool, for example, with a pool starting at 10.0.0.2 :
|
||||
|
||||
- 10.0.0.2 : vm1
|
||||
- 10.0.0.3 : vm2
|
||||
- 10.0.0.4 : DHCP server
|
||||
- 10.0.0.5 : vm3
|
||||
|
||||
When this stack is imported in Heat, the DHCP server IP is set to the lowest
|
||||
free IP address of its pool. Depending on the VM creation order, the DHCP
|
||||
address can either collide with vm1's or vm2's IP.
|
||||
|
||||
|
@ -13,6 +13,7 @@ To use the CLI of flame::
|
||||
[--os-auth-token OS_AUTH_TOKEN] [--insecure]
|
||||
[--endpoint_type ENDPOINT_TYPE] [--exclude-servers]
|
||||
[--exclude-volumes] [--exclude-keypairs] [--generate-stack-data]
|
||||
[--extract-ports]
|
||||
|
||||
Heat template and data file generator
|
||||
|
||||
@ -38,6 +39,7 @@ To use the CLI of flame::
|
||||
--generate-stack-data
|
||||
In addition to template, generate Heat stack data
|
||||
file.
|
||||
--extract-ports Export the tenant network ports
|
||||
|
||||
|
||||
Example
|
||||
|
@ -34,11 +34,12 @@ class Client(object):
|
||||
**kwargs)
|
||||
|
||||
def generate(self, exclude_servers, exclude_volumes, exclude_keypairs,
|
||||
generate_stack_data):
|
||||
generate_stack_data, extract_ports=False):
|
||||
self.template_generator.extract_vm_details(exclude_servers,
|
||||
exclude_volumes,
|
||||
exclude_keypairs,
|
||||
generate_stack_data
|
||||
generate_stack_data,
|
||||
extract_ports
|
||||
)
|
||||
self.template_generator.extract_data()
|
||||
return self.template_generator.heat_template_and_data()
|
||||
|
@ -80,6 +80,9 @@ def main(args=None):
|
||||
default=False,
|
||||
help="In addition to template, generate Heat "
|
||||
"stack data file.")
|
||||
parser.add_argument('--extract-ports', action='store_true',
|
||||
default=False,
|
||||
help="Export the tenant network ports")
|
||||
|
||||
args = parser.parse_args()
|
||||
flame = client.Client(args.username, args.password,
|
||||
@ -92,7 +95,8 @@ def main(args=None):
|
||||
template.extract_vm_details(args.exclude_servers,
|
||||
args.exclude_volumes,
|
||||
args.exclude_keypairs,
|
||||
args.generate_stack_data)
|
||||
args.generate_stack_data,
|
||||
args.extract_ports)
|
||||
template.extract_data()
|
||||
print("### Heat Template ###")
|
||||
print(template.heat_template_and_data())
|
||||
|
@ -158,12 +158,25 @@ class TemplateGenerator(object):
|
||||
res_type = future_res[res_available]
|
||||
yield res_type, fetch_map[res_type][1](res)
|
||||
|
||||
def order_ports(self):
|
||||
for i, port in self.ports.values():
|
||||
for fixed_ip in port['fixed_ips']:
|
||||
ip_subnet = self.subnets[fixed_ip['subnet_id']][1]
|
||||
pools = ip_subnet.get('allocation_pools')
|
||||
if pools:
|
||||
pools_starts = [pool['start'] for pool in pools]
|
||||
if fixed_ip['ip_address'] in pools_starts:
|
||||
# Its the first port of the subnet
|
||||
ip_subnet['first_port'] = port
|
||||
|
||||
def extract_vm_details(self, exclude_servers, exclude_volumes,
|
||||
exclude_keypairs, generate_data):
|
||||
exclude_keypairs, generate_data,
|
||||
extract_ports=False):
|
||||
self.exclude_servers = exclude_servers
|
||||
self.exclude_volumes = exclude_volumes
|
||||
self.exclude_keypairs = exclude_keypairs
|
||||
self.generate_data = generate_data
|
||||
self.extract_ports = extract_ports
|
||||
self.external_networks = []
|
||||
fetch_map = {
|
||||
'subnets': (self.neutron.subnet_list, self.build_data),
|
||||
@ -174,6 +187,7 @@ class TemplateGenerator(object):
|
||||
'floatingips': (self.neutron.floatingip_list, lambda x: x),
|
||||
'ports': (self.neutron.port_list, self.build_data),
|
||||
}
|
||||
|
||||
if not exclude_keypairs:
|
||||
fetch_map['keys'] = (self.nova.keypair_list,
|
||||
lambda l: {key.name: (index, key) for
|
||||
@ -189,6 +203,7 @@ class TemplateGenerator(object):
|
||||
|
||||
for res_type, result in self.async_fetch_data(fetch_map):
|
||||
self.__setattr__(res_type, result)
|
||||
self.order_ports()
|
||||
|
||||
def build_data(self, data):
|
||||
if not data:
|
||||
@ -289,6 +304,22 @@ class TemplateGenerator(object):
|
||||
def get_subnet_resource_name(self, subnet_id):
|
||||
return "subnet_%d" % self.subnets[subnet_id][0]
|
||||
|
||||
def get_server_resource_name(self, device_id):
|
||||
return "server_%d" % self.servers[device_id][0]
|
||||
|
||||
def get_router_resource_name(self, device_id):
|
||||
return "router_%d" % self.routers[device_id][0]
|
||||
|
||||
def get_secgroup_resource_name(self, secgroup_id):
|
||||
return "security_group_%d" % self.secgroups[secgroup_id][0]
|
||||
|
||||
def get_ports_for_server(self, server_id):
|
||||
ports = []
|
||||
for n, port in self.ports.values():
|
||||
if port['device_id'] == server_id:
|
||||
ports.append("port_%d" % n)
|
||||
return ports
|
||||
|
||||
def _extract_subnets(self):
|
||||
resources = []
|
||||
for n, subnet in self.subnets.values():
|
||||
@ -311,11 +342,56 @@ class TemplateGenerator(object):
|
||||
resources.append(resource)
|
||||
return resources
|
||||
|
||||
def _extract_ports(self):
|
||||
resources = []
|
||||
resources_dict = {}
|
||||
self.dhcp_fixed_ips = {}
|
||||
for n, port in self.ports.values():
|
||||
fixed_ips = []
|
||||
for fixed_ip_dict in port['fixed_ips']:
|
||||
subnet_id = fixed_ip_dict['subnet_id']
|
||||
subnet_name = self.get_subnet_resource_name(subnet_id)
|
||||
fixed_ip_resource = {u'subnet_id':
|
||||
{'get_resource': subnet_name},
|
||||
u'ip_address': fixed_ip_dict['ip_address']
|
||||
}
|
||||
fixed_ips.append(fixed_ip_resource)
|
||||
|
||||
if port['device_owner'] == 'network:dhcp':
|
||||
# Add the fixed ip to the dhcp_fixed_ips list
|
||||
dhcp_ips = self.dhcp_fixed_ips.setdefault(subnet_name, [])
|
||||
dhcp_ips.append(fixed_ip_dict['ip_address'])
|
||||
if not port['device_owner'].startswith('compute:'):
|
||||
# It's not a server, skip it!
|
||||
continue
|
||||
net_name = self.get_network_resource_name(port['network_id'])
|
||||
properties = {
|
||||
'network_id': {'get_resource': net_name},
|
||||
'admin_state_up': port['admin_state_up'],
|
||||
'fixed_ips': fixed_ips,
|
||||
'mac_address': port['mac_address'],
|
||||
'device_owner': port['device_owner'],
|
||||
}
|
||||
if port['name'] != '':
|
||||
# This port has a name
|
||||
properties['name'] = port['name']
|
||||
resource = Resource("port_%d" % n, 'OS::Neutron::Port',
|
||||
port['id'], properties)
|
||||
security_groups = self.build_port_secgroups(resource, port)
|
||||
properties['security_groups'] = security_groups
|
||||
|
||||
resources.append(resource)
|
||||
resources_dict[port['id']] = resource
|
||||
|
||||
return resources
|
||||
|
||||
def _build_rules(self, rules):
|
||||
brules = []
|
||||
for rule in rules:
|
||||
if rule['protocol'] == 'any':
|
||||
del rule['protocol']
|
||||
del rule['port_range_min']
|
||||
del rule['port_range_max']
|
||||
rg_id = rule['remote_group_id']
|
||||
if rg_id is not None:
|
||||
rule['remote_mode'] = "remote_group_id"
|
||||
@ -396,6 +472,31 @@ class TemplateGenerator(object):
|
||||
|
||||
return security_groups
|
||||
|
||||
def build_port_secgroups(self, resource, port):
|
||||
security_groups = []
|
||||
port_secgroups = [self.secgroups[sgid][1]
|
||||
for sgid in port['security_groups']]
|
||||
|
||||
secgroup_default_parameter = None
|
||||
for secgr in port_secgroups:
|
||||
if secgr['name'] == 'default' and self.generate_data:
|
||||
if not secgroup_default_parameter:
|
||||
port_res_name = 'port_%d' % self.ports[port['id']][0]
|
||||
param_name = "%s_default_security_group" % port_res_name
|
||||
description = ("Default security group for port %s" %
|
||||
port['name'])
|
||||
default = secgr['id']
|
||||
resource.add_parameter(param_name, description,
|
||||
default=default)
|
||||
secgroup_default_parameter = {'get_param': param_name}
|
||||
security_groups.append(secgroup_default_parameter)
|
||||
else:
|
||||
resource_name = ("security_group_%d" %
|
||||
self.secgroups[secgr['id']][0])
|
||||
security_groups.append({'get_resource': resource_name})
|
||||
|
||||
return security_groups
|
||||
|
||||
def build_networks(self, addresses):
|
||||
networks = []
|
||||
for net_name in addresses:
|
||||
@ -460,13 +561,19 @@ class TemplateGenerator(object):
|
||||
resource_key = "key_%d" % self.keys[server.key_name][0]
|
||||
properties['key_name'] = {'get_resource': resource_key}
|
||||
|
||||
security_groups = self.build_secgroups(resource, server)
|
||||
if security_groups:
|
||||
properties['security_groups'] = security_groups
|
||||
if self.extract_ports:
|
||||
ports = [{"port": {"get_resource": port}}
|
||||
for port in self.get_ports_for_server(server.id)]
|
||||
if ports:
|
||||
properties['networks'] = ports
|
||||
else:
|
||||
security_groups = self.build_secgroups(resource, server)
|
||||
if security_groups:
|
||||
properties['security_groups'] = security_groups
|
||||
|
||||
networks = self.build_networks(server.addresses)
|
||||
if networks:
|
||||
properties['networks'] = networks
|
||||
networks = self.build_networks(server.addresses)
|
||||
if networks:
|
||||
properties['networks'] = networks
|
||||
|
||||
if server.metadata:
|
||||
properties['metadata'] = server.metadata
|
||||
@ -526,20 +633,36 @@ class TemplateGenerator(object):
|
||||
default=default)
|
||||
resources.append(resource)
|
||||
|
||||
if not self.exclude_servers and ip['port_id']:
|
||||
device = self.ports[ip['port_id']][1]['device_id']
|
||||
if device and self.servers[device]:
|
||||
server = self.servers[device]
|
||||
server_resource_name = "server_%d" % server[0]
|
||||
properties = {
|
||||
'floating_ip': {'get_resource': ip_resource_name},
|
||||
'server_id': {'get_resource': server_resource_name}
|
||||
}
|
||||
resource = Resource("floatingip_association_%d" % n,
|
||||
'OS::Nova::FloatingIPAssociation',
|
||||
None,
|
||||
properties)
|
||||
resources.append(resource)
|
||||
if self.extract_ports and ip['port_id']:
|
||||
port_number = self.ports[ip['port_id']][0]
|
||||
port_resource_name = "port_%d" % port_number
|
||||
properties = {
|
||||
'floatingip_id': {'get_resource': ip_resource_name},
|
||||
'port_id': {'get_resource': port_resource_name}
|
||||
}
|
||||
resource_id = ("%s:%s" %
|
||||
(ip['id'],
|
||||
ip['port_id']))
|
||||
resource = Resource("floatingip_association_%d" % n,
|
||||
'OS::Neutron::FloatingIPAssociation',
|
||||
resource_id,
|
||||
properties)
|
||||
resources.append(resource)
|
||||
else:
|
||||
if not self.exclude_servers and ip['port_id']:
|
||||
device = self.ports[ip['port_id']][1]['device_id']
|
||||
if device and self.servers[device]:
|
||||
server = self.servers[device]
|
||||
server_resource_name = "server_%d" % server[0]
|
||||
properties = {
|
||||
'floating_ip': {'get_resource': ip_resource_name},
|
||||
'server_id': {'get_resource': server_resource_name}
|
||||
}
|
||||
resource = Resource("floatingip_association_%d" % n,
|
||||
'OS::Nova::FloatingIPAssociation',
|
||||
None,
|
||||
properties)
|
||||
resources.append(resource)
|
||||
return resources
|
||||
|
||||
def _extract_volumes(self):
|
||||
@ -596,6 +719,9 @@ class TemplateGenerator(object):
|
||||
def extract_data(self):
|
||||
resources = self._extract_routers()
|
||||
resources += self._extract_networks()
|
||||
if self.extract_ports:
|
||||
resources += self._extract_ports()
|
||||
|
||||
resources += self._extract_subnets()
|
||||
resources += self._extract_secgroups()
|
||||
resources += self._extract_floating()
|
||||
|
@ -22,6 +22,7 @@
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
import mock
|
||||
import yaml
|
||||
|
||||
@ -274,11 +275,12 @@ class BaseTestCase(base.TestCase):
|
||||
super(BaseTestCase, self).tearDown()
|
||||
|
||||
def get_generator(self, exclude_servers, exclude_volumes,
|
||||
exclude_keypairs, generate_data):
|
||||
exclude_keypairs, generate_data, extract_ports):
|
||||
generator = flame.TemplateGenerator('x', 'x', 'x', 'x', True,
|
||||
'publicURL')
|
||||
generator.extract_vm_details(exclude_servers, exclude_volumes,
|
||||
exclude_keypairs, generate_data)
|
||||
exclude_keypairs, generate_data,
|
||||
extract_ports)
|
||||
return generator
|
||||
|
||||
def check_stackdata(self, resources, expected_resources):
|
||||
@ -304,7 +306,7 @@ class BaseTestCase(base.TestCase):
|
||||
|
||||
class TemplateGenerationTest(BaseTestCase):
|
||||
def test_heat_template_and_data_with_data(self):
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
generator.extract_data()
|
||||
out = yaml.load(generator.heat_template_and_data())
|
||||
mandatory_keys = set(('environment', 'template', 'resources',
|
||||
@ -316,7 +318,7 @@ class TemplateGenerationTest(BaseTestCase):
|
||||
self.assertEqual(generator.stack_data, out)
|
||||
|
||||
def test_heat_template_and_data_without_data(self):
|
||||
generator = self.get_generator(False, False, False, False)
|
||||
generator = self.get_generator(False, False, False, False, False)
|
||||
generator.extract_data()
|
||||
out = yaml.load(generator.heat_template_and_data())
|
||||
mandatory_keys = {'heat_template_version', 'resources', 'description',
|
||||
@ -343,7 +345,7 @@ class ClientTest(BaseTestCase):
|
||||
self.assertNotIn('template', parsed_out.keys())
|
||||
|
||||
def test_generate_contains_extract(self):
|
||||
out = self.c.generate(False, False, False, True)
|
||||
out = self.c.generate(False, False, False, True, False)
|
||||
parsed_out = yaml.load(out)
|
||||
self.assertIsInstance(parsed_out, dict)
|
||||
self.assertIn('template', parsed_out.keys())
|
||||
@ -353,7 +355,7 @@ class StackDataTests(BaseTestCase):
|
||||
|
||||
def test_keypair(self):
|
||||
self.mock_nova.return_value = FakeNovaManager()
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected = {
|
||||
'key_0': {
|
||||
@ -370,7 +372,7 @@ class StackDataTests(BaseTestCase):
|
||||
|
||||
def test_router(self):
|
||||
self.mock_neutron.return_value = FakeNeutronManager()
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected = {
|
||||
'router_0': {
|
||||
@ -393,8 +395,10 @@ class StackDataTests(BaseTestCase):
|
||||
'external_gateway_info': {
|
||||
'network_id': '8765',
|
||||
'enable_snat': 'true'}}, ]
|
||||
# This router has no port
|
||||
fake.ports = []
|
||||
self.mock_neutron.return_value = fake
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected = {
|
||||
'router_0': {
|
||||
@ -447,7 +451,7 @@ class StackDataTests(BaseTestCase):
|
||||
'id': '1111'}, ]
|
||||
|
||||
self.mock_neutron.return_value = fake
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected = {
|
||||
'router_0': {
|
||||
@ -473,7 +477,7 @@ class StackDataTests(BaseTestCase):
|
||||
|
||||
def test_network(self):
|
||||
self.mock_neutron.return_value = FakeNeutronManager()
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected = {
|
||||
'network_0': {
|
||||
@ -493,7 +497,7 @@ class StackDataTests(BaseTestCase):
|
||||
fake.networks[0]['router:external'] = True
|
||||
self.mock_neutron.return_value = fake
|
||||
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
self.check_stackdata(generator._extract_networks(), {})
|
||||
|
||||
@ -512,7 +516,7 @@ class StackDataTests(BaseTestCase):
|
||||
'id': '1111'}, ]
|
||||
self.mock_neutron.return_value = fake
|
||||
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected = {
|
||||
'subnet_0': {
|
||||
@ -538,7 +542,7 @@ class StackDataTests(BaseTestCase):
|
||||
'id': '2222'}, ]
|
||||
self.mock_neutron.return_value = fake
|
||||
|
||||
generator = self.get_generator(True, False, False, True)
|
||||
generator = self.get_generator(True, False, False, True, False)
|
||||
|
||||
expected = {
|
||||
'floatingip_0': {
|
||||
@ -572,7 +576,7 @@ class StackDataTests(BaseTestCase):
|
||||
'id': '1234'}, ]
|
||||
self.mock_neutron.return_value = fake
|
||||
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected = {
|
||||
'security_group_0': {
|
||||
@ -606,14 +610,14 @@ class StackDataTests(BaseTestCase):
|
||||
'id': '1234'}, ]
|
||||
self.mock_neutron.return_value = fake
|
||||
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
self.check_stackdata(generator._extract_secgroups(), {})
|
||||
|
||||
def test_volume(self):
|
||||
self.mock_cinder.return_value = FakeCinderManager()
|
||||
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected = {
|
||||
'volume_0': {
|
||||
@ -631,7 +635,7 @@ class StackDataTests(BaseTestCase):
|
||||
def test_server(self):
|
||||
self.mock_nova.return_value = FakeNovaManager()
|
||||
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected = {
|
||||
'server_0': {
|
||||
@ -658,7 +662,7 @@ class StackDataTests(BaseTestCase):
|
||||
self.mock_neutron.return_value = fake_neutron
|
||||
self.mock_nova.return_value = fake_nova
|
||||
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected = {
|
||||
'server_0': {
|
||||
@ -675,7 +679,7 @@ class StackDataTests(BaseTestCase):
|
||||
|
||||
def test_servergroup(self):
|
||||
self.mock_nova.return_value = FakeNovaManager()
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected = {
|
||||
'servergroup_0': {
|
||||
@ -695,7 +699,7 @@ class NetworkTests(BaseTestCase):
|
||||
|
||||
def test_keypair(self):
|
||||
self.mock_nova.return_value = FakeNovaManager()
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected = {
|
||||
'key_0': {
|
||||
@ -710,7 +714,8 @@ class NetworkTests(BaseTestCase):
|
||||
|
||||
def test_router(self):
|
||||
self.mock_neutron.return_value = FakeNeutronManager()
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
self.mock_neutron.return_value.ports = []
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected = {
|
||||
'router_0': {
|
||||
@ -725,6 +730,7 @@ class NetworkTests(BaseTestCase):
|
||||
|
||||
def test_router_with_external_gateway(self):
|
||||
fake = FakeNeutronManager()
|
||||
fake.ports = []
|
||||
fake.routers = [{'name': 'myrouter',
|
||||
'id': '1234',
|
||||
'admin_state_up': 'true',
|
||||
@ -732,7 +738,7 @@ class NetworkTests(BaseTestCase):
|
||||
'network_id': '8765',
|
||||
'enable_snat': 'true'}}, ]
|
||||
self.mock_neutron.return_value = fake
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected_parameters = {
|
||||
'router_0_external_network': {
|
||||
@ -791,7 +797,7 @@ class NetworkTests(BaseTestCase):
|
||||
'id': '1111'}, ]
|
||||
|
||||
self.mock_neutron.return_value = fake
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected = {
|
||||
'router_0': {
|
||||
@ -813,7 +819,7 @@ class NetworkTests(BaseTestCase):
|
||||
|
||||
def test_network(self):
|
||||
self.mock_neutron.return_value = FakeNeutronManager()
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected = {
|
||||
'network_0': {
|
||||
@ -832,7 +838,7 @@ class NetworkTests(BaseTestCase):
|
||||
fake.networks[0]['router:external'] = True
|
||||
self.mock_neutron.return_value = fake
|
||||
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
self.check_template(generator._extract_networks(), {})
|
||||
|
||||
@ -851,7 +857,7 @@ class NetworkTests(BaseTestCase):
|
||||
'id': '1111'}, ]
|
||||
self.mock_neutron.return_value = fake
|
||||
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected = {
|
||||
'subnet_0': {
|
||||
@ -882,7 +888,7 @@ class NetworkTests(BaseTestCase):
|
||||
'id': '2222'}, ]
|
||||
self.mock_neutron.return_value = fake
|
||||
|
||||
generator = self.get_generator(True, False, False, False)
|
||||
generator = self.get_generator(True, False, False, False, False)
|
||||
|
||||
expected_parameters = {
|
||||
'external_network_for_floating_ip_0': {
|
||||
@ -963,7 +969,7 @@ class NetworkTests(BaseTestCase):
|
||||
'id': '1234'}, ]
|
||||
self.mock_neutron.return_value = fake
|
||||
|
||||
generator = self.get_generator(False, False, False, False)
|
||||
generator = self.get_generator(False, False, False, False, False)
|
||||
|
||||
expected = {
|
||||
'security_group_0': {
|
||||
@ -1073,7 +1079,7 @@ class NetworkTests(BaseTestCase):
|
||||
'id': '1111'}, ]
|
||||
self.mock_neutron.return_value = fake
|
||||
|
||||
generator = self.get_generator(False, False, False, False)
|
||||
generator = self.get_generator(False, False, False, False, False)
|
||||
|
||||
expected = {
|
||||
'security_group_0': {
|
||||
@ -1229,7 +1235,7 @@ class NetworkTests(BaseTestCase):
|
||||
'id': '2222'}, ]
|
||||
self.mock_neutron.return_value = fake
|
||||
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected = {
|
||||
'security_group_0': {
|
||||
@ -1317,7 +1323,7 @@ class VolumeTests(BaseTestCase):
|
||||
self.mock_cinder.return_value = self.fake
|
||||
|
||||
def test_basic(self):
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected_parameters = {
|
||||
'volume_0_volume_type': {
|
||||
@ -1342,7 +1348,7 @@ class VolumeTests(BaseTestCase):
|
||||
|
||||
def test_basic_unnamed(self):
|
||||
self.fake.volumes = [FakeUnnamedVolume(), ]
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected_parameters = {
|
||||
'volume_0_volume_type': {
|
||||
@ -1365,7 +1371,7 @@ class VolumeTests(BaseTestCase):
|
||||
|
||||
def test_source_volid_external(self):
|
||||
self.fake.volumes = [FakeVolume(source_volid=5678), ]
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected_parameters = {
|
||||
'volume_0_source_volid': {
|
||||
@ -1395,7 +1401,7 @@ class VolumeTests(BaseTestCase):
|
||||
def test_source_volid_included(self):
|
||||
self.fake.volumes = [FakeVolume(source_volid=5678),
|
||||
FakeVolume(id=5678)]
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected_parameters = {
|
||||
'volume_0_volume_type': {
|
||||
@ -1448,7 +1454,7 @@ class VolumeTests(BaseTestCase):
|
||||
'size': '25'}
|
||||
self.fake.volumes = [FakeVolume(bootable='true',
|
||||
volume_image_metadata=metadata), ]
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected_parameters = {
|
||||
'volume_0_volume_type': {
|
||||
@ -1479,7 +1485,7 @@ class VolumeTests(BaseTestCase):
|
||||
|
||||
def test_snapshot_id(self):
|
||||
self.fake.volumes = [FakeVolume(snapshot_id=5678), ]
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected_parameters = {
|
||||
'volume_0_snapshot_id': {
|
||||
@ -1510,7 +1516,7 @@ class VolumeTests(BaseTestCase):
|
||||
|
||||
def test_volume_type(self):
|
||||
self.fake.volumes = [FakeVolume(volume_type='isci'), ]
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected_parameters = {
|
||||
'volume_0_volume_type': {
|
||||
@ -1535,7 +1541,7 @@ class VolumeTests(BaseTestCase):
|
||||
|
||||
def test_metadata(self):
|
||||
self.fake.volumes = [FakeVolume(metadata={'key': 'value'}), ]
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected_parameters = {
|
||||
'volume_0_volume_type': {
|
||||
@ -1568,7 +1574,7 @@ class ServerTests(BaseTestCase):
|
||||
self.mock_nova.return_value = self.fake
|
||||
|
||||
def test_basic(self):
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected_parameters = {
|
||||
'server_0_flavor': {
|
||||
@ -1599,7 +1605,7 @@ class ServerTests(BaseTestCase):
|
||||
|
||||
def test_keypair(self):
|
||||
self.fake.servers = [FakeServer(key_name='testkey')]
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected_parameters = {
|
||||
'server_0_flavor': {
|
||||
@ -1645,7 +1651,7 @@ class ServerTests(BaseTestCase):
|
||||
bootable='true')]
|
||||
self.mock_cinder.return_value = fake_cinder
|
||||
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected_parameters = {
|
||||
'server_0_flavor': {
|
||||
@ -1683,7 +1689,7 @@ class ServerTests(BaseTestCase):
|
||||
server_args = {"id": 777,
|
||||
"os-extended-volumes:volumes_attached": [{'id': 5678}]}
|
||||
self.fake.servers = [FakeServer(**server_args), ]
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected_parameters = {
|
||||
'server_0_flavor': {
|
||||
@ -1723,7 +1729,7 @@ class ServerTests(BaseTestCase):
|
||||
"description": "Group"}, ]
|
||||
self.mock_neutron.return_value = fake_neutron
|
||||
self.fake.groups = {'server1': [FakeSecurityGroup(), ]}
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected_parameters = {
|
||||
'server_0_flavor': {
|
||||
@ -1760,7 +1766,7 @@ class ServerTests(BaseTestCase):
|
||||
|
||||
def test_config_drive(self):
|
||||
self.fake.servers = [FakeServer(config_drive="True"), ]
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected_parameters = {
|
||||
'server_0_flavor': {
|
||||
@ -1792,7 +1798,7 @@ class ServerTests(BaseTestCase):
|
||||
|
||||
def test_metadata(self):
|
||||
self.fake.servers = [FakeServer(metadata={"key": "value"}), ]
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected_parameters = {
|
||||
'server_0_flavor': {
|
||||
@ -1839,7 +1845,7 @@ class ServerTests(BaseTestCase):
|
||||
self.mock_neutron.return_value = fake_neutron
|
||||
addresses = {"private": [{"addr": "10.0.0.2"}]}
|
||||
self.fake.servers = [FakeServer(addresses=addresses)]
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected_parameters = {
|
||||
'server_0_flavor': {
|
||||
@ -1883,7 +1889,7 @@ class ServerTests(BaseTestCase):
|
||||
server_args = {"id": 777,
|
||||
"os-extended-volumes:volumes_attached": [{'id': 5678}]}
|
||||
self.fake.servers = [FakeServer(**server_args), ]
|
||||
generator = self.get_generator(False, True, False, False)
|
||||
generator = self.get_generator(False, True, False, False, False)
|
||||
|
||||
expected_parameters = {
|
||||
'server_0_flavor': {
|
||||
@ -1924,7 +1930,7 @@ class ServerTests(BaseTestCase):
|
||||
def test_servergroup(self):
|
||||
self.fake.servers = [FakeServer()]
|
||||
self.fake.servers[0].id = '12345'
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected_parameters = {
|
||||
'server_0_flavor': {
|
||||
@ -1966,7 +1972,7 @@ class GenerationTests(BaseTestCase):
|
||||
|
||||
def test_generation(self):
|
||||
|
||||
generator = self.get_generator(False, False, False, True)
|
||||
generator = self.get_generator(False, False, False, True, False)
|
||||
|
||||
expected_parameters = {
|
||||
'server_0_flavor': {
|
||||
@ -2098,7 +2104,7 @@ class GenerationTests(BaseTestCase):
|
||||
|
||||
def test_generation_exclude_servers(self):
|
||||
|
||||
generator = self.get_generator(True, False, False, True)
|
||||
generator = self.get_generator(True, False, False, True, False)
|
||||
|
||||
expected_parameters = {
|
||||
'volume_0_volume_type': {
|
||||
@ -2204,7 +2210,7 @@ class GenerationTests(BaseTestCase):
|
||||
|
||||
def test_generation_exclude_volumes(self):
|
||||
|
||||
generator = self.get_generator(False, True, False, True)
|
||||
generator = self.get_generator(False, True, False, True, False)
|
||||
|
||||
expected_parameters = {
|
||||
'server_0_flavor': {
|
||||
@ -2314,7 +2320,7 @@ class GenerationTests(BaseTestCase):
|
||||
|
||||
def test_generation_exclude_keypairs(self):
|
||||
|
||||
generator = self.get_generator(False, False, True, True)
|
||||
generator = self.get_generator(False, False, True, True, False)
|
||||
|
||||
expected_parameters = {
|
||||
'server_0_flavor': {
|
||||
@ -2437,7 +2443,7 @@ class GenerationTests(BaseTestCase):
|
||||
|
||||
def test_generation_exclude_servers_and_volumes(self):
|
||||
|
||||
generator = self.get_generator(True, True, False, True)
|
||||
generator = self.get_generator(True, True, False, True, False)
|
||||
|
||||
expected_parameters = {}
|
||||
expected_resources = {
|
||||
@ -2517,7 +2523,7 @@ class GenerationTests(BaseTestCase):
|
||||
|
||||
def test_generation_exclude_servers_volumes_keypairs(self):
|
||||
|
||||
generator = self.get_generator(True, True, True, True)
|
||||
generator = self.get_generator(True, True, True, True, False)
|
||||
|
||||
expected_parameters = {}
|
||||
expected_resources = {
|
||||
|
640
flameclient/tests/test_flameports.py
Normal file
640
flameclient/tests/test_flameports.py
Normal file
@ -0,0 +1,640 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2014 Cloudwatt
|
||||
|
||||
# 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 re
|
||||
|
||||
import mock
|
||||
|
||||
from flameclient import flame
|
||||
from flameclient.tests import base
|
||||
|
||||
|
||||
class FakeBase(object):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
for key, value in kwargs.items():
|
||||
setattr(self, key, value)
|
||||
|
||||
|
||||
class FakeVolume(FakeBase):
|
||||
id = 1234
|
||||
size = 1
|
||||
source_volid = None
|
||||
bootable = 'false'
|
||||
snapshot_id = None
|
||||
display_name = 'vol1'
|
||||
display_description = 'Description'
|
||||
volume_type = 'fast'
|
||||
metadata = None
|
||||
|
||||
|
||||
class FakeServer(FakeBase):
|
||||
id = '1234'
|
||||
name = 'server1'
|
||||
config_drive = None
|
||||
flavor = {'id': '2'}
|
||||
image = {'id': '3333',
|
||||
'links': [{'href': 'http://p/7777/images/3333',
|
||||
'rel': 'bookmark'}]}
|
||||
key_name = 'testkey'
|
||||
addresses = []
|
||||
metadata = None
|
||||
|
||||
def __init__(self, server_id, **kwargs):
|
||||
self.id = server_id
|
||||
kwargs.setdefault('OS-DCF:diskConfig', 'MANUAL')
|
||||
kwargs.setdefault('os-extended-volumes:volumes_attached', [])
|
||||
super(FakeServer, self).__init__(**kwargs)
|
||||
|
||||
|
||||
class FakeFlavor(FakeBase):
|
||||
name = 'm1.tiny'
|
||||
id = '1'
|
||||
|
||||
|
||||
class FakeKeypair(FakeBase):
|
||||
name = 'key'
|
||||
id = 'key'
|
||||
public_key = 'ssh-rsa AAAAB3NzaC'
|
||||
|
||||
|
||||
class FakeSecurityGroup(FakeBase):
|
||||
id = '1'
|
||||
name = 'name'
|
||||
|
||||
|
||||
class FakeNeutronManager(object):
|
||||
|
||||
def __init__(self):
|
||||
self.groups = [{u'description': u'default',
|
||||
u'id': u'secgorup1',
|
||||
u'name': u'default',
|
||||
u'security_group_rules': [
|
||||
{u'direction': u'ingress',
|
||||
u'ethertype': u'IPv4',
|
||||
u'id': u'secgroup-rule1',
|
||||
u'port_range_max': 65535,
|
||||
u'port_range_min': 1,
|
||||
u'protocol': u'tcp',
|
||||
u'remote_group_id': None,
|
||||
u'remote_ip_prefix': u'0.0.0.0/0',
|
||||
u'security_group_id': u'secgorup1',
|
||||
u'tenant_id': u'tenant1'},
|
||||
],
|
||||
u'tenant_id': u'tenant1'}]
|
||||
|
||||
self.routers = [
|
||||
{u'admin_state_up': True,
|
||||
u'external_gateway_info': {u'enable_snat': True,
|
||||
u'network_id': u'network3'},
|
||||
u'id': u'router1',
|
||||
u'name': u'gw-internal-a',
|
||||
u'routes': [],
|
||||
u'status': u'ACTIVE',
|
||||
u'tenant_id': u'tenant1'},
|
||||
]
|
||||
|
||||
self.ports = [{u'admin_state_up': True,
|
||||
u'allowed_address_pairs': [],
|
||||
u'binding:vnic_type': u'normal',
|
||||
u'device_id': u'router1',
|
||||
u'device_owner': u'network:router_interface',
|
||||
u'extra_dhcp_opts': [],
|
||||
u'fixed_ips': [{u'ip_address': u'192.168.203.1',
|
||||
u'subnet_id': u'subnet3'}],
|
||||
u'id': u'port1',
|
||||
u'mac_address': u'fa:16:3e:fe:c1:b3',
|
||||
u'name': u'',
|
||||
u'network_id': u'network1',
|
||||
u'security_groups': [],
|
||||
u'status': u'ACTIVE',
|
||||
u'tenant_id': u'tenant1'},
|
||||
{u'admin_state_up': True,
|
||||
u'allowed_address_pairs': [],
|
||||
u'binding:vnic_type': u'normal',
|
||||
u'device_id': u'server3',
|
||||
u'device_owner': u'compute:nova',
|
||||
u'extra_dhcp_opts': [],
|
||||
u'fixed_ips': [{u'ip_address': u'192.168.203.5',
|
||||
u'subnet_id': u'subnet3'}],
|
||||
u'id': u'port2',
|
||||
u'mac_address': u'fa:16:3e:e4:44:7b',
|
||||
u'name': u'',
|
||||
u'network_id': u'network1',
|
||||
u'security_groups': [u'secgorup1'],
|
||||
u'status': u'ACTIVE',
|
||||
u'tenant_id': u'tenant1'},
|
||||
{u'admin_state_up': True,
|
||||
u'allowed_address_pairs': [],
|
||||
u'binding:vnic_type': u'normal',
|
||||
u'device_id': u'server2',
|
||||
u'device_owner': u'compute:nova',
|
||||
u'extra_dhcp_opts': [],
|
||||
u'fixed_ips': [{u'ip_address': u'192.168.203.4',
|
||||
u'subnet_id': u'subnet3'}],
|
||||
u'id': u'port3',
|
||||
u'mac_address': u'fa:16:3e:e8:e4:e2',
|
||||
u'name': u'',
|
||||
u'network_id': u'network1',
|
||||
u'security_groups': [u'secgorup1'],
|
||||
u'status': u'ACTIVE',
|
||||
u'tenant_id': u'tenant1'},
|
||||
{u'admin_state_up': True,
|
||||
u'allowed_address_pairs': [],
|
||||
u'binding:vnic_type': u'normal',
|
||||
u'device_id': u'dhcp1-network1',
|
||||
u'device_owner': u'network:dhcp',
|
||||
u'extra_dhcp_opts': [],
|
||||
u'fixed_ips': [{u'ip_address': u'192.168.203.3',
|
||||
u'subnet_id': u'subnet3'},
|
||||
{u'ip_address': u'192.168.204.2',
|
||||
u'subnet_id': u'subnet4'}],
|
||||
u'id': u'port4',
|
||||
u'mac_address': u'fa:16:3e:af:86:30',
|
||||
u'name': u'',
|
||||
u'network_id': u'network1',
|
||||
u'security_groups': [],
|
||||
u'status': u'ACTIVE',
|
||||
u'tenant_id': u'tenant1'},
|
||||
{u'admin_state_up': True,
|
||||
u'allowed_address_pairs': [],
|
||||
u'binding:vnic_type': u'normal',
|
||||
u'device_id': u'server1',
|
||||
u'device_owner': u'compute:nova',
|
||||
u'extra_dhcp_opts': [],
|
||||
u'fixed_ips': [{u'ip_address': u'192.168.203.2',
|
||||
u'subnet_id': u'subnet3'}],
|
||||
u'id': u'port6',
|
||||
u'mac_address': u'fa:16:3e:b0:9a:e2',
|
||||
u'name': u'',
|
||||
u'network_id': u'network1',
|
||||
u'security_groups': [u'secgorup1'],
|
||||
u'status': u'ACTIVE',
|
||||
u'tenant_id': u'tenant1'}
|
||||
]
|
||||
self.subnets = [{u'allocation_pools': [
|
||||
{u'end': u'172.19.0.254', u'start': u'172.19.0.2'}],
|
||||
u'cidr': u'172.19.0.0/24',
|
||||
u'dns_nameservers': [],
|
||||
u'enable_dhcp': True,
|
||||
u'gateway_ip': u'172.19.0.1',
|
||||
u'host_routes': [],
|
||||
u'id': u'subnet1',
|
||||
u'ip_version': 4,
|
||||
u'name': u'storage',
|
||||
u'network_id': u'network2',
|
||||
u'tenant_id': u'tenant1'},
|
||||
{u'allocation_pools': [
|
||||
{u'end': u'10.8.8.200',
|
||||
u'start': u'10.8.8.100'}],
|
||||
u'cidr': u'10.8.8.0/24',
|
||||
u'dns_nameservers': [],
|
||||
u'enable_dhcp': False,
|
||||
u'gateway_ip': u'10.8.8.254',
|
||||
u'host_routes': [],
|
||||
u'id': u'subnet2',
|
||||
u'ip_version': 4,
|
||||
u'name': u'ext-subnet',
|
||||
u'network_id': u'network3',
|
||||
u'tenant_id': u'tenant1'},
|
||||
{u'allocation_pools': [{u'end': u'192.168.203.254',
|
||||
u'start': u'192.168.203.2'}],
|
||||
u'cidr': u'192.168.203.0/24',
|
||||
u'dns_nameservers': [],
|
||||
u'enable_dhcp': True,
|
||||
u'gateway_ip': u'192.168.203.1',
|
||||
u'host_routes': [],
|
||||
u'id': u'subnet3',
|
||||
u'ip_version': 4,
|
||||
u'name': u'int-a-1',
|
||||
u'network_id': u'network1',
|
||||
u'tenant_id': u'tenant1'},
|
||||
{u'allocation_pools': [{u'end': u'192.168.204.254',
|
||||
u'start': u'192.168.204.2'}],
|
||||
u'cidr': u'192.168.204.0/24',
|
||||
u'dns_nameservers': [],
|
||||
u'enable_dhcp': True,
|
||||
u'gateway_ip': u'192.168.204.1',
|
||||
u'host_routes': [],
|
||||
u'id': u'subnet4',
|
||||
u'ip_version': 4,
|
||||
u'name': u'int-a-2',
|
||||
u'network_id': u'network1',
|
||||
u'tenant_id': u'tenant1'}]
|
||||
self.networks = [{u'admin_state_up': True,
|
||||
u'id': u'network1',
|
||||
u'name': u'internal',
|
||||
u'router:external': False,
|
||||
u'shared': False,
|
||||
u'status': u'ACTIVE',
|
||||
u'subnets': [u'subnet3',
|
||||
u'subnet4'],
|
||||
u'tenant_id': u'tenant1'},
|
||||
{u'admin_state_up': True,
|
||||
u'id': u'network2',
|
||||
u'name': u'storage',
|
||||
u'router:external': False,
|
||||
u'shared': False,
|
||||
u'status': u'ACTIVE',
|
||||
u'subnets': [u'subnet1'],
|
||||
u'tenant_id': u'tenant1'},
|
||||
{u'admin_state_up': True,
|
||||
u'id': u'network3',
|
||||
u'name': u'ext-net',
|
||||
u'router:external': True,
|
||||
u'shared': True,
|
||||
u'status': u'ACTIVE',
|
||||
u'subnets': [u'subnet2'],
|
||||
u'tenant_id': u'tenant1'}]
|
||||
|
||||
self.floatingips = [{u'fixed_ip_address': None,
|
||||
u'floating_ip_address': u'10.8.8.102',
|
||||
u'floating_network_id': u'network3',
|
||||
u'id': u'floating1',
|
||||
u'port_id': None,
|
||||
u'router_id': None,
|
||||
u'status': u'DOWN',
|
||||
u'tenant_id': u'tenant1'},
|
||||
{u'fixed_ip_address': None,
|
||||
u'floating_ip_address': u'10.8.8.101',
|
||||
u'floating_network_id': u'network3',
|
||||
u'id': u'floating2',
|
||||
u'port_id': None,
|
||||
u'router_id': None,
|
||||
u'status': u'DOWN',
|
||||
u'tenant_id': u'tenant1'},
|
||||
{u'fixed_ip_address': u'192.168.203.4',
|
||||
u'floating_ip_address': u'10.8.8.168',
|
||||
u'floating_network_id': u'network3',
|
||||
u'id': u'floating3',
|
||||
u'port_id': u'port3',
|
||||
u'router_id': u'router1',
|
||||
u'status': u'ACTIVE',
|
||||
u'tenant_id': u'tenant1'},
|
||||
{u'fixed_ip_address': None,
|
||||
u'floating_ip_address': u'10.8.8.118',
|
||||
u'floating_network_id': u'network3',
|
||||
u'id': u'floating4',
|
||||
u'port_id': None,
|
||||
u'router_id': None,
|
||||
u'status': u'DOWN',
|
||||
u'tenant_id': u'tenant1'}]
|
||||
|
||||
def subnet_list(self):
|
||||
return self.subnets
|
||||
|
||||
def network_list(self):
|
||||
return self.networks
|
||||
|
||||
def port_list(self):
|
||||
return self.ports
|
||||
|
||||
def router_list(self):
|
||||
return self.routers
|
||||
|
||||
def router_interfaces_list(self, router):
|
||||
return [port for port in self.ports
|
||||
if port['device_id'] == router['id']]
|
||||
|
||||
def secgroup_list(self):
|
||||
return self.groups
|
||||
|
||||
def floatingip_list(self):
|
||||
return self.floatingips
|
||||
|
||||
|
||||
class FakeNovaManager(object):
|
||||
|
||||
def __init__(self):
|
||||
self.servers = [FakeServer('server1'),
|
||||
FakeServer('server2'),
|
||||
FakeServer('server3')]
|
||||
self.servergroups = []
|
||||
self.flavors = [FakeFlavor(id='2', name='m1.small')]
|
||||
self.groups = {}
|
||||
self.keypairs = [FakeKeypair(name='testkey',
|
||||
public_key='ssh-rsa XXXX')]
|
||||
|
||||
def keypair_list(self):
|
||||
return self.keypairs
|
||||
|
||||
def flavor_list(self):
|
||||
return self.flavors
|
||||
|
||||
def server_list(self):
|
||||
return self.servers
|
||||
|
||||
def server_security_group_list(self, server):
|
||||
return self.groups.get(server.name, [])
|
||||
|
||||
def servergroup_list(self):
|
||||
return self.servergroups
|
||||
|
||||
|
||||
class FakeCinderManager(object):
|
||||
|
||||
def __init__(self):
|
||||
self.volumes = [FakeVolume(), ]
|
||||
|
||||
def volume_list(self):
|
||||
return self.volumes
|
||||
|
||||
|
||||
class ResourceTestCase(base.TestCase):
|
||||
|
||||
def test_template_resource(self):
|
||||
resource = flame.Resource('my-name',
|
||||
'my-type',
|
||||
properties='my-properties')
|
||||
|
||||
expected = {
|
||||
'my-name': {
|
||||
'type': 'my-type',
|
||||
'properties': 'my-properties',
|
||||
}
|
||||
}
|
||||
self.assertEqual(expected, resource.template_resource)
|
||||
|
||||
|
||||
class BaseTestCase(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(BaseTestCase, self).setUp()
|
||||
self.patch_neutron = mock.patch('flameclient.managers.NeutronManager')
|
||||
self.mock_neutron = self.patch_neutron.start()
|
||||
self.patch_nova = mock.patch('flameclient.managers.NovaManager')
|
||||
self.mock_nova = self.patch_nova.start()
|
||||
self.patch_cinder = mock.patch('flameclient.managers.CinderManager')
|
||||
self.mock_cinder = self.patch_cinder.start()
|
||||
|
||||
def tearDown(self):
|
||||
self.mock_neutron.stop()
|
||||
self.mock_nova.stop()
|
||||
self.mock_cinder.stop()
|
||||
super(BaseTestCase, self).tearDown()
|
||||
|
||||
def get_generator(self, exclude_servers, exclude_volumes,
|
||||
exclude_keypairs, generate_data, extract_ports):
|
||||
generator = flame.TemplateGenerator('x', 'x', 'x', 'x', True,
|
||||
'publicURL')
|
||||
generator.extract_vm_details(exclude_servers, exclude_volumes,
|
||||
exclude_keypairs, generate_data,
|
||||
extract_ports)
|
||||
return generator
|
||||
|
||||
def check_stackdata(self, resources, expected_resources):
|
||||
merged_resources = {}
|
||||
for resource in resources:
|
||||
merged_resources.update(resource.stack_resource)
|
||||
|
||||
self.assertEqual(expected_resources, merged_resources)
|
||||
|
||||
def check_template(self, resources, expected_resources,
|
||||
expected_parameters=None):
|
||||
|
||||
expected_parameters = expected_parameters or {}
|
||||
merged_resources = {}
|
||||
merged_parameters = {}
|
||||
for resource in resources:
|
||||
merged_resources.update(resource.template_resource)
|
||||
merged_parameters.update(resource.template_parameter)
|
||||
|
||||
self.assertEqual(expected_resources, merged_resources)
|
||||
self.assertEqual(expected_parameters, merged_parameters)
|
||||
|
||||
|
||||
class StackDataTests(BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(StackDataTests, self).setUp()
|
||||
self.mock_neutron.return_value = FakeNeutronManager()
|
||||
self.mock_nova.return_value = FakeNovaManager()
|
||||
self.mock_cinder.return_value = FakeCinderManager()
|
||||
|
||||
def test_routers_presents(self):
|
||||
generator = self.get_generator(False, False, False, True, True)
|
||||
extraction = generator._extract_routers()
|
||||
routers = {r.name: r for r in extraction}
|
||||
self.assertIn('router_0', routers)
|
||||
|
||||
def test_routers_resource_names(self):
|
||||
generator = self.get_generator(False, False, False, True, True)
|
||||
generator_output = generator._extract_routers()
|
||||
routers = (res for res in generator_output
|
||||
if res.type == "OS::Neutron::Router")
|
||||
for n, router in enumerate(routers):
|
||||
assert(router.name.startswith("router_"))
|
||||
|
||||
def test_ports_presents(self):
|
||||
generator = self.get_generator(False, False, False, True, True)
|
||||
extraction = generator._extract_ports()
|
||||
ports = {r.name: r for r in extraction}
|
||||
self.assertIn('port_1', ports)
|
||||
self.assertIn('port_2', ports)
|
||||
|
||||
def test_ports_resource_names_types(self):
|
||||
generator = self.get_generator(False, False, False, True, True)
|
||||
extraction = generator._extract_ports()
|
||||
for n, port in enumerate(extraction):
|
||||
props = port.properties
|
||||
assert(extraction[0].name.startswith("port_"))
|
||||
self.assertEqual("OS::Neutron::Port", port.type)
|
||||
self.assertIsInstance(props['admin_state_up'], bool)
|
||||
self.assertIsInstance(props['security_groups'], list)
|
||||
assert(props['device_owner'].startswith("compute:"))
|
||||
|
||||
def test_port_fixed_ip(self):
|
||||
reference = [{'ip_address': '192.168.203.2',
|
||||
'subnet_id': {'get_resource': 'subnet_2'}}]
|
||||
generator = self.get_generator(False, False, False, True, True)
|
||||
extraction = generator._extract_ports()
|
||||
# Get the right port for the test
|
||||
port = next((p for p in extraction if
|
||||
p.properties['mac_address'] == 'fa:16:3e:b0:9a:e2'))
|
||||
props = port.properties
|
||||
self.assertIsInstance(props['fixed_ips'], list)
|
||||
fixed_ips = props['fixed_ips']
|
||||
for ref in reference:
|
||||
self.assertIn(ref, fixed_ips)
|
||||
|
||||
def test_servers_ports_assignations(self):
|
||||
generator = self.get_generator(False, False, False, True, True)
|
||||
extraction = generator._extract_servers()
|
||||
used_ports = []
|
||||
for n, server in enumerate(extraction):
|
||||
props = server.properties
|
||||
self.assertIsInstance(props['networks'], list)
|
||||
for network in props['networks']:
|
||||
port = network['port']['get_resource']
|
||||
assert(port.startswith("port_"))
|
||||
# Port has not been used by another server
|
||||
self.assertNotIn(port, used_ports)
|
||||
used_ports.append(port)
|
||||
|
||||
def test_floating_association(self):
|
||||
generator = self.get_generator(False, False, False, True, True)
|
||||
extraction = generator._extract_floating()
|
||||
associations = (res for res in extraction
|
||||
if res.type == "OS::Neutron::FloatingIPAssociation")
|
||||
for association in associations:
|
||||
props = association.properties
|
||||
assert(props['floatingip_id']['get_resource'].
|
||||
startswith('floatingip_'))
|
||||
assert(props['port_id']['get_resource'].
|
||||
startswith('port_'))
|
||||
|
||||
|
||||
class GenerationTests(BaseTestCase):
|
||||
resource_ref = set(['floatingip_association_2',
|
||||
'subnet_2', 'subnet_3', 'subnet_0',
|
||||
'port_2', 'port_1', 'port_4',
|
||||
'server_2', 'server_1', 'server_0',
|
||||
'router_0',
|
||||
'router_0_interface_0',
|
||||
'router_0_gateway',
|
||||
'key_0',
|
||||
'network_0', 'network_1',
|
||||
'floatingip_0', 'floatingip_1',
|
||||
'floatingip_2', 'floatingip_3',
|
||||
'volume_0'])
|
||||
|
||||
params_ref = set(['volume_0_volume_type',
|
||||
'external_network_for_floating_ip_3',
|
||||
'external_network_for_floating_ip_2',
|
||||
'external_network_for_floating_ip_1',
|
||||
'external_network_for_floating_ip_0',
|
||||
'port_4_default_security_group',
|
||||
'port_1_default_security_group',
|
||||
'port_2_default_security_group',
|
||||
'router_0_external_network',
|
||||
'server_1_image',
|
||||
'server_1_flavor',
|
||||
'server_1_key',
|
||||
'server_2_image',
|
||||
'server_2_flavor',
|
||||
'server_2_key',
|
||||
'server_0_image',
|
||||
'server_0_flavor',
|
||||
'server_0_key'])
|
||||
|
||||
data_ref = set(['floatingip_0', 'floatingip_1', 'floatingip_2',
|
||||
'floatingip_3',
|
||||
'floatingip_association_2',
|
||||
'key_0',
|
||||
'network_0', 'network_1',
|
||||
'port_1', 'port_2', 'port_4',
|
||||
'router_0',
|
||||
'router_0_gateway',
|
||||
'router_0_interface_0',
|
||||
'server_0', 'server_1', 'server_2',
|
||||
'subnet_0', 'subnet_2', 'subnet_3',
|
||||
'volume_0'])
|
||||
|
||||
def filter_set(self, filtered_set, exclude):
|
||||
excluded_set = set()
|
||||
for exc in exclude:
|
||||
excluded_set.update(
|
||||
set([e for e in filtered_set if re.search(exc, e)])
|
||||
)
|
||||
return filtered_set.difference(excluded_set)
|
||||
|
||||
def setUp(self):
|
||||
super(GenerationTests, self).setUp()
|
||||
self.mock_neutron.return_value = FakeNeutronManager()
|
||||
self.mock_nova.return_value = FakeNovaManager()
|
||||
self.mock_cinder.return_value = FakeCinderManager()
|
||||
|
||||
def test_generation(self):
|
||||
|
||||
exclusion_table = [
|
||||
{'call_params': (False, False, False, True, True),
|
||||
'resource_filter': [],
|
||||
'params_filter': ['^server_\d+_key$'],
|
||||
'data_filter': []},
|
||||
# No server
|
||||
{'call_params': (True, False, False, True, True),
|
||||
'resource_filter': ['^server'],
|
||||
'params_filter': ['^server'],
|
||||
'data_filter': ['^server']},
|
||||
# No volumes
|
||||
{'call_params': (False, True, False, True, True),
|
||||
'resource_filter': ['^volume'],
|
||||
'params_filter': [r'^volume_\d+_volume_type$',
|
||||
'^server_\d+_key$'],
|
||||
'data_filter': ['^volume']},
|
||||
# No keys
|
||||
{'call_params': (False, False, True, True, True),
|
||||
'resource_filter': ['^key_\d+$'],
|
||||
'params_filter': [],
|
||||
'data_filter': ['^key', 'server_\d+_key']},
|
||||
# No ports
|
||||
{'call_params': (False, False, False, True, False),
|
||||
'resource_filter': ['^port_\d+$'],
|
||||
'params_filter': ['^port_\d+_default_security_group$',
|
||||
'server_\d+_key$'],
|
||||
'data_filter': ['^port_\d+', '^floatingip_association_\d+$']},
|
||||
]
|
||||
|
||||
for exclusion in exclusion_table:
|
||||
generator = self.get_generator(*exclusion['call_params'])
|
||||
resource_ref = self.filter_set(self.resource_ref,
|
||||
exclusion['resource_filter'])
|
||||
params_ref = self.filter_set(self.params_ref,
|
||||
exclusion['params_filter'])
|
||||
data_ref = self.filter_set(self.data_ref,
|
||||
exclusion['data_filter'])
|
||||
|
||||
generator.extract_data()
|
||||
# All the resources, params and datas are present
|
||||
self.assertEqual(resource_ref,
|
||||
set(generator.template['resources'].keys()),
|
||||
"Called with : %r" % (exclusion['call_params'],))
|
||||
self.assertEqual(params_ref,
|
||||
set(generator.template['parameters'].keys()),
|
||||
"Called with : %r" % (exclusion['call_params'],))
|
||||
self.assertEqual(data_ref,
|
||||
set(generator.stack_data['resources'].keys()),
|
||||
"Called with : %r" % (exclusion['call_params'],))
|
||||
|
||||
def test_floating_association_data(self):
|
||||
generator = self.get_generator(False, False, False, True, True)
|
||||
generator.extract_data()
|
||||
# Look for floating ips
|
||||
assoc_name = 'floatingip_association_2'
|
||||
association_data = generator.stack_data['resources'][assoc_name]
|
||||
reference = {'action': 'CREATE',
|
||||
'metadata': {},
|
||||
'name': 'floatingip_association_2',
|
||||
'resource_data': {},
|
||||
'resource_id': u'floating3:port3',
|
||||
'status': 'COMPLETE',
|
||||
'type': 'OS::Neutron::FloatingIPAssociation'}
|
||||
self.assertEqual(reference, association_data)
|
||||
|
||||
def test_port_data(self):
|
||||
generator = self.get_generator(False, False, False, True, True)
|
||||
generator.extract_data()
|
||||
# Look for floating ips
|
||||
assoc_name = 'port_2'
|
||||
association_data = generator.stack_data['resources'][assoc_name]
|
||||
reference = {'action': 'CREATE',
|
||||
'metadata': {},
|
||||
'name': 'port_2',
|
||||
'resource_data': {},
|
||||
'resource_id': u'port3',
|
||||
'status': 'COMPLETE',
|
||||
'type': 'OS::Neutron::Port'}
|
||||
self.assertEqual(reference, association_data)
|
Loading…
Reference in New Issue
Block a user