diff --git a/vmtp/compute.py b/vmtp/compute.py index 1c539ef..14cf99d 100644 --- a/vmtp/compute.py +++ b/vmtp/compute.py @@ -147,13 +147,13 @@ class Compute(object): # and check that it gets into the ACTIVE state def create_server(self, vmname, image, flavor, key_name, nic, sec_group, avail_zone=None, user_data=None, - config_drive=None, - retry_count=10): + config_drive=None, files=None, retry_count=10): if sec_group: security_groups = [sec_group.name] else: security_groups = None + # Also attach the created security group for the test instance = self.novaclient.servers.create(name=vmname, image=image, @@ -163,6 +163,7 @@ class Compute(object): availability_zone=avail_zone, userdata=user_data, config_drive=config_drive, + files=files, security_groups=security_groups) if not instance: return None diff --git a/vmtp/instance.py b/vmtp/instance.py index af884e3..7b5bebd 100644 --- a/vmtp/instance.py +++ b/vmtp/instance.py @@ -17,7 +17,7 @@ import re from log import LOG import monitor -from netaddr import IPAddress +import netaddr import sshutils @@ -55,7 +55,8 @@ class Instance(object): self.gmond_port = int(config.gmond_svr_port) else: self.gmond_port = 0 - self.config_drive = None + self.config_drive = config.config_drive + self.no_floatingip = config.no_floatingip # Setup the ssh connectivity # this function is only used for native hosts @@ -70,6 +71,42 @@ class Instance(object): connect_retry_count=self.config.ssh_retry_count) return True + def get_network_interface(self, port_info): + ip_address = port_info['fixed_ips'][0]['ip_address'] + subnet_id = port_info['fixed_ips'][0]['subnet_id'] + subnet_info = self.net.neutron_client.show_subnet(subnet_id)['subnet'] + + cidr = netaddr.IPNetwork(subnet_info['cidr']) + network_dict = { + 'ip_address': ip_address, + 'netmask': str(cidr.netmask), + 'network': str(cidr.network), + 'broadcast': str(cidr.broadcast), + 'gateway': subnet_info['gateway_ip'], + 'dns': '' + } + if subnet_info['dns_nameservers']: + dns_servers = ','.join(subnet_info['dns_nameservers']) + network_dict['dns'] = 'dns-nameservers %s\n' % dns_servers + + retStr = ( + '# The loopback network interface\n' + 'auto lo\n' + 'iface lo inet loopback\n' + '\n' + '# The primary network interface\n' + 'auto eth0\n' + 'iface eth0 inet static\n' + ' address %(ip_address)s\n' + ' netmask %(netmask)s\n' + ' network %(network)s\n' + ' broadcast %(broadcast)s\n' + ' gateway %(gateway)s\n' + ' %(dns)s' + ) % network_dict + + return retStr + # Create a new VM instance, associate a floating IP for ssh access # and extract internal network IP # Retruns True if success, False otherwise @@ -90,7 +127,7 @@ class Instance(object): else: user_data = None - if self.config.vnic_type: + if self.config.vnic_type or self.config.no_dhcp: # create the VM by passing a port ID instead of a net ID self.port = self.net.create_port(int_net['id'], [sec_group.id], @@ -103,6 +140,11 @@ class Instance(object): # create the VM by passing a net ID nics = [{'net-id': int_net['id']}] + files = None + if self.config.no_dhcp: + network_interface = self.get_network_interface(self.port) + files = {'/etc/network/interfaces': network_interface} + self.instance = self.comp.create_server(self.name, image, flavor_type, @@ -112,6 +154,7 @@ class Instance(object): az, user_data, self.config_drive, + files, self.config.generic_retry_count) if user_data: user_data.close() @@ -130,7 +173,7 @@ class Instance(object): else: # Set the internal ip to the correct ip for v4 and v6 for ip_address in self.instance.networks[internal_network_name]: - ip = IPAddress(ip_address) + ip = netaddr.IPAddress(ip_address) if self.config.ipv6_mode: if ip.version == 6: self.internal_ip = ip_address @@ -140,14 +183,17 @@ class Instance(object): if ip.version == 4: self.internal_ip = ip_address ipv4_fixed_address = ip_address - fip = self.net.create_floating_ip() - if not fip: - self.display('Floating ip creation failed') - return False - self.ssh_access.host = fip['floatingip']['floating_ip_address'] - self.ssh_ip_id = fip['floatingip']['id'] - self.display('Associating floating IP %s', self.ssh_access.host) - self.instance.add_floating_ip(self.ssh_access.host, ipv4_fixed_address) + if self.no_floatingip: + self.ssh_access.host = self.internal_ip + else: + fip = self.net.create_floating_ip() + if not fip: + self.display('Floating ip creation failed.') + return False + self.ssh_access.host = fip['floatingip']['floating_ip_address'] + self.ssh_ip_id = fip['floatingip']['id'] + self.display('Associating floating IP %s', self.ssh_access.host) + self.instance.add_floating_ip(self.ssh_access.host, ipv4_fixed_address) # extract the IP for the data network self.display('Internal network IP: %s', self.internal_ip) diff --git a/vmtp/network.py b/vmtp/network.py index c8d2c4e..91fa95d 100644 --- a/vmtp/network.py +++ b/vmtp/network.py @@ -75,35 +75,34 @@ class Network(object): self.ext_net = network break - if not self.ext_net: - LOG.error("No external network found.") - return + if self.ext_net: + LOG.info("Using external network: " + self.ext_net['name']) + # Find or create the router to the external network + ext_net_id = self.ext_net['id'] + routers = neutron_client.list_routers()['routers'] + for router in routers: + external_gw_info = router['external_gateway_info'] + if external_gw_info: + if external_gw_info['network_id'] == ext_net_id: + self.ext_router = router + LOG.info('Found external router: %s' % (self.ext_router['name'])) + break - LOG.info("Using external network: " + self.ext_net['name']) - - # Find or create the router to the external network - ext_net_id = self.ext_net['id'] - routers = neutron_client.list_routers()['routers'] - for router in routers: - external_gw_info = router['external_gateway_info'] - if external_gw_info: - if external_gw_info['network_id'] == ext_net_id: - self.ext_router = router - LOG.info('Found external router: %s' % (self.ext_router['name'])) - break - - # create a new external router if none found and a name was given - self.ext_router_name = config.router_name - if (not self.ext_router) and self.ext_router_name: - self.ext_router = self.create_router(self.ext_router_name, - self.ext_net['id']) - LOG.info('Created ext router %s.' % (self.ext_router_name)) - self.ext_router_created = True + # create a new external router if none found and a name was given + self.ext_router_name = config.router_name + if (not self.ext_router) and self.ext_router_name: + self.ext_router = self.create_router(self.ext_router_name, + self.ext_net['id']) + LOG.info('Created ext router %s.' % (self.ext_router_name)) + self.ext_router_created = True + else: + LOG.warning("No external network found.") if config.ipv6_mode: self.ipv6_enabled = True # Create the networks and subnets depending on v4 or v6 + enable_dhcp = not config.no_dhcp if config.ipv6_mode: for (net, subnet, cidr, subnet_v6, cidr_v6) in zip(config.internal_network_name, config.internal_subnet_name, @@ -112,7 +111,8 @@ class Network(object): config.internal_cidr_v6): int_net = self.create_net(net, subnet, cidr, config.dns_nameservers, - subnet_v6, cidr_v6, config.ipv6_mode) + subnet_v6, cidr_v6, config.ipv6_mode, + enable_dhcp=enable_dhcp) self.vm_int_net.append(int_net) if config.same_network_only: break @@ -121,14 +121,16 @@ class Network(object): config.internal_subnet_name, config.internal_cidr): int_net = self.create_net(net, subnet, cidr, - config.dns_nameservers) + config.dns_nameservers, + enable_dhcp=enable_dhcp) self.vm_int_net.append(int_net) if config.same_network_only: break # Add both internal networks to router interface to enable # network to network connectivity - self.__add_router_interface() + if self.ext_net: + self.__add_router_interface() self.l2agent_type = self._get_l2agent_type() self.internal_iface_dict = self._get_internal_iface_dict() @@ -138,7 +140,8 @@ class Network(object): # return that network. # dns_nameservers: a list of name servers e.g. ['8.8.8.8'] def create_net(self, network_name, subnet_name, cidr, dns_nameservers, - subnet_name_ipv6=None, cidr_ipv6=None, ipv6_mode=None): + subnet_name_ipv6=None, cidr_ipv6=None, ipv6_mode=None, + enable_dhcp=True): for network in self.networks: if network['name'] == network_name: @@ -162,6 +165,9 @@ class Network(object): 'dns_nameservers': dns_nameservers } } + if not enable_dhcp: + body['subnet']['enable_dhcp'] = False + subnet = self.neutron_client.create_subnet(body)['subnet'] # add subnet id to the network dict since it has just been added network['subnets'] = [subnet['id']] @@ -178,6 +184,8 @@ class Network(object): 'ipv6_address_mode': ipv6_mode } } + if not enable_dhcp: + body['subnet']['enable_dhcp'] = False subnet = self.neutron_client.create_subnet(body)['subnet'] # add the subnet id to the network dict network['subnets'].append(subnet['id']) @@ -253,6 +261,9 @@ class Network(object): # May fail with neutronclient.common.exceptions.Conflict # if there are floating IP in use - just ignore LOG.warning('Router interface may have floating IP in use: not deleted') + except TypeError: + # Externel router is not existed, so let's just continue + pass # Lookup network given network name def lookup_network(self, network_name): @@ -304,7 +315,7 @@ class Network(object): body['port']['binding:vnic_type'] = vnic_type port = self.neutron_client.create_port(body) if self.config.debug: - LOG.info('Created port ' + port['port']['id']) + LOG.debug('Created port ' + port['port']['id']) return port['port'] def delete_port(self, port): diff --git a/vmtp/perf_instance.py b/vmtp/perf_instance.py index 81c7573..57575cc 100644 --- a/vmtp/perf_instance.py +++ b/vmtp/perf_instance.py @@ -30,11 +30,6 @@ class PerfInstance(Instance): self.tp_tool = config.tp_tool(self) else: self.tp_tool = None - # Override the config drive option to save in instance - if config.config_drive: - self.config_drive = True - else: - self.config_drive = None # No args is reserved for native host server def create(self, image=None, flavor_type=None, diff --git a/vmtp/vmtp.py b/vmtp/vmtp.py index e45a8d1..f7bf0e9 100755 --- a/vmtp/vmtp.py +++ b/vmtp/vmtp.py @@ -270,8 +270,8 @@ class VmtpTest(object): self.config.internal_network_name = int_net_name else: # Make sure we have an external network and an external router - self.assert_true(self.net.ext_net) - self.assert_true(self.net.ext_router) + # self.assert_true(self.net.ext_net) + # self.assert_true(self.net.ext_router) self.assert_true(self.net.vm_int_net) # Get hosts for the availability zone to use @@ -826,6 +826,22 @@ def parse_opts_from_cli(): help='binding vnic type for test VMs', metavar='') + parser.add_argument('--no-dhcp', dest='no_dhcp', + default=False, + action='store_true', + help='Assign IP address to guest instance') + + parser.add_argument('--no-floatingip', dest='no_floatingip', + default=False, + action='store_true', + help='Do not assign floating IP to guest instance') + + parser.add_argument('--use-config-drive', dest='config_drive', + default=False, + action='store_true', + help='Use config drive to configure guest instance. Enable this option ' + 'when metadata service is not available') + parser.add_argument('-d', '--debug', dest='debug', default=False, action='store_true', @@ -979,6 +995,9 @@ def merge_opts_to_configs(opts): if opts.os_dataplane_network: config.os_dataplane_network = opts.os_dataplane_network + config.config_drive = opts.config_drive + config.no_floatingip = opts.no_floatingip + config.no_dhcp = opts.no_dhcp config.delete_image_after_run = opts.delete_image_after_run #####################################################