Bootable volume support (bump)
Change-Id: I2989587204766dc1dfc51979608a691578d1f660
This commit is contained in:
parent
34a82c9f35
commit
5ac228a575
11
.zuul.yaml
Normal file
11
.zuul.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
- project:
|
||||||
|
check:
|
||||||
|
jobs:
|
||||||
|
- openstack-tox-pep8
|
||||||
|
- openstack-tox-py36
|
||||||
|
- openstack-tox-docs
|
||||||
|
gate:
|
||||||
|
jobs:
|
||||||
|
- openstack-tox-pep8
|
||||||
|
- openstack-tox-py36
|
||||||
|
- openstack-tox-docs
|
@ -7,11 +7,11 @@ hacking<1.2.0,>=1.1.0 # Apache-2.0
|
|||||||
coverage!=4.4 # Apache-2.0
|
coverage!=4.4 # Apache-2.0
|
||||||
discover
|
discover
|
||||||
python-subunit # Apache-2.0/BSD
|
python-subunit # Apache-2.0/BSD
|
||||||
sphinx!=1.6.6,!=1.6.7,<2.0.0;python_version=='2.7' # BSD
|
|
||||||
sphinx!=1.6.6,!=1.6.7;python_version>='3.4' # BSD
|
sphinx!=1.6.6,!=1.6.7;python_version>='3.4' # BSD
|
||||||
sphinx-rtd-theme>=0.1.9
|
sphinx-rtd-theme>=0.1.9
|
||||||
oslosphinx # Apache-2.0
|
oslosphinx # Apache-2.0
|
||||||
oslotest # Apache-2.0
|
oslotest # Apache-2.0
|
||||||
|
pyflakes==2.1.1
|
||||||
testrepository # Apache-2.0/BSD
|
testrepository # Apache-2.0/BSD
|
||||||
testscenarios # Apache-2.0/BSD
|
testscenarios # Apache-2.0/BSD
|
||||||
testtools # MIT
|
testtools # MIT
|
||||||
|
@ -149,16 +149,21 @@ class Compute(object):
|
|||||||
# and check that it gets into the ACTIVE state
|
# and check that it gets into the ACTIVE state
|
||||||
def create_server(self, vmname, image, flavor, key_name,
|
def create_server(self, vmname, image, flavor, key_name,
|
||||||
nic, sec_group, avail_zone=None, user_data=None,
|
nic, sec_group, avail_zone=None, user_data=None,
|
||||||
config_drive=None, files=None, retry_count=10):
|
config_drive=None, files=None, retry_count=10, volume=None):
|
||||||
|
|
||||||
if sec_group:
|
if sec_group:
|
||||||
security_groups = [sec_group["name"]]
|
security_groups = [sec_group["name"]]
|
||||||
else:
|
else:
|
||||||
security_groups = None
|
security_groups = None
|
||||||
|
|
||||||
# Also attach the created security group for the test
|
# Also attach the created security group for the test
|
||||||
|
vol_map = None
|
||||||
|
if volume:
|
||||||
|
vol_map = [{"source_type": "volume", "boot_index": "0",
|
||||||
|
"uuid": volume.id, "destination_type": "volume"}]
|
||||||
|
image = None
|
||||||
instance = self.novaclient.servers.create(name=vmname,
|
instance = self.novaclient.servers.create(name=vmname,
|
||||||
image=image,
|
image=image,
|
||||||
|
block_device_mapping_v2=vol_map,
|
||||||
flavor=flavor,
|
flavor=flavor,
|
||||||
key_name=key_name,
|
key_name=key_name,
|
||||||
nics=nic,
|
nics=nic,
|
||||||
@ -363,7 +368,7 @@ class Compute(object):
|
|||||||
if len(avail_list) == 2:
|
if len(avail_list) == 2:
|
||||||
break
|
break
|
||||||
LOG.info('Using hypervisors ' + ', '.join(avail_list))
|
LOG.info('Using hypervisors ' + ', '.join(avail_list))
|
||||||
else:
|
if len(avail_list) < 2:
|
||||||
for host in host_list:
|
for host in host_list:
|
||||||
# this host must be a compute node
|
# this host must be a compute node
|
||||||
if host.binary != 'nova-compute' or host.state != 'up' or host.status != 'enabled':
|
if host.binary != 'nova-compute' or host.state != 'up' or host.status != 'enabled':
|
||||||
@ -374,7 +379,7 @@ class Compute(object):
|
|||||||
candidate = self.normalize_az_host(None, host.host)
|
candidate = self.normalize_az_host(None, host.host)
|
||||||
else:
|
else:
|
||||||
candidate = self.normalize_az_host(host.zone, host.host)
|
candidate = self.normalize_az_host(host.zone, host.host)
|
||||||
if candidate:
|
if candidate and candidate not in avail_list:
|
||||||
avail_list.append(candidate)
|
avail_list.append(candidate)
|
||||||
# pick first 2 matches at most
|
# pick first 2 matches at most
|
||||||
if len(avail_list) == 2:
|
if len(avail_list) == 2:
|
||||||
|
@ -146,7 +146,8 @@ class Instance(object):
|
|||||||
az,
|
az,
|
||||||
internal_network_name,
|
internal_network_name,
|
||||||
sec_group,
|
sec_group,
|
||||||
init_file_name=None):
|
init_file_name=None,
|
||||||
|
volume=None):
|
||||||
# if ssh is created it means this is a native host not a vm
|
# if ssh is created it means this is a native host not a vm
|
||||||
if self.ssh:
|
if self.ssh:
|
||||||
return True
|
return True
|
||||||
@ -185,7 +186,8 @@ class Instance(object):
|
|||||||
user_data,
|
user_data,
|
||||||
self.config_drive,
|
self.config_drive,
|
||||||
files,
|
files,
|
||||||
self.config.generic_retry_count)
|
self.config.generic_retry_count,
|
||||||
|
volume)
|
||||||
if user_data:
|
if user_data:
|
||||||
user_data.close()
|
user_data.close()
|
||||||
if not self.instance:
|
if not self.instance:
|
||||||
|
@ -36,7 +36,7 @@ class PerfInstance(Instance):
|
|||||||
ssh_access=None, nics=None, az=None,
|
ssh_access=None, nics=None, az=None,
|
||||||
management_network_name=None,
|
management_network_name=None,
|
||||||
sec_group=None,
|
sec_group=None,
|
||||||
init_file_name=None):
|
init_file_name=None, volume=None):
|
||||||
'''Create an instance
|
'''Create an instance
|
||||||
:return: True on success, False on error
|
:return: True on success, False on error
|
||||||
'''
|
'''
|
||||||
@ -44,7 +44,7 @@ class PerfInstance(Instance):
|
|||||||
nics, az,
|
nics, az,
|
||||||
management_network_name,
|
management_network_name,
|
||||||
sec_group,
|
sec_group,
|
||||||
init_file_name)
|
init_file_name, volume)
|
||||||
if not rc:
|
if not rc:
|
||||||
return False
|
return False
|
||||||
if self.tp_tool and not self.tp_tool.install():
|
if self.tp_tool and not self.tp_tool.install():
|
||||||
|
73
vmtp/vmtp.py
73
vmtp/vmtp.py
@ -24,6 +24,7 @@ import pprint
|
|||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
import time
|
||||||
|
|
||||||
from .__init__ import __version__
|
from .__init__ import __version__
|
||||||
from . import compute
|
from . import compute
|
||||||
@ -31,8 +32,11 @@ from .config import config_load
|
|||||||
from .config import config_loads
|
from .config import config_loads
|
||||||
from . import credentials
|
from . import credentials
|
||||||
from .fluentd import FluentLogHandler
|
from .fluentd import FluentLogHandler
|
||||||
|
import cinderclient.exceptions as cinder_exception
|
||||||
|
from cinderclient.v2 import client as cinderclient
|
||||||
from glanceclient.v2 import client as glanceclient
|
from glanceclient.v2 import client as glanceclient
|
||||||
from . import iperf_tool
|
from . import iperf_tool
|
||||||
|
import keystoneauth1
|
||||||
from keystoneclient import client as keystoneclient
|
from keystoneclient import client as keystoneclient
|
||||||
from .log import CONLOG
|
from .log import CONLOG
|
||||||
from .log import FILELOG
|
from .log import FILELOG
|
||||||
@ -159,6 +163,14 @@ class VmtpTest(object):
|
|||||||
def create_instance(self, inst, az, int_net):
|
def create_instance(self, inst, az, int_net):
|
||||||
fn = self.config.user_data_file
|
fn = self.config.user_data_file
|
||||||
user_data_file = fn if fn and os.path.isfile(fn) else None
|
user_data_file = fn if fn and os.path.isfile(fn) else None
|
||||||
|
volume = None
|
||||||
|
if self.config.volume:
|
||||||
|
volume = self.create_volume(self.cinder_client,
|
||||||
|
self.image_instance,
|
||||||
|
self.config.image_name + "_" +
|
||||||
|
inst.name + "_" + time.strftime('%d%m_%H%M%S'),
|
||||||
|
self.config.volume)
|
||||||
|
|
||||||
self.assert_true(inst.create(self.image_instance,
|
self.assert_true(inst.create(self.image_instance,
|
||||||
self.flavor_type,
|
self.flavor_type,
|
||||||
self.instance_access,
|
self.instance_access,
|
||||||
@ -166,12 +178,49 @@ class VmtpTest(object):
|
|||||||
az,
|
az,
|
||||||
int_net['name'],
|
int_net['name'],
|
||||||
self.sec_group,
|
self.sec_group,
|
||||||
init_file_name=user_data_file))
|
init_file_name=user_data_file,
|
||||||
|
volume=volume))
|
||||||
|
|
||||||
def assert_true(self, cond):
|
def assert_true(self, cond):
|
||||||
if not cond:
|
if not cond:
|
||||||
raise VmtpException('Assert failure')
|
raise VmtpException('Assert failure')
|
||||||
|
|
||||||
|
def create_volume(self, cinder_client, image, vol_name, vol_size):
|
||||||
|
LOG.info('Creating new volume: {}'.format(vol_name))
|
||||||
|
retry = 0
|
||||||
|
retry_count = 60
|
||||||
|
volume = cinder_client.volumes.create(name=str(vol_name), size=vol_size, imageRef=image.id)
|
||||||
|
while volume.status in ['creating', 'downloading'] and retry < retry_count:
|
||||||
|
try:
|
||||||
|
volume = cinder_client.volumes.find(name=volume.name)
|
||||||
|
except (cinder_exception.NotFound, keystoneauth1.exceptions.http.NotFound):
|
||||||
|
pass
|
||||||
|
retry = retry + 1
|
||||||
|
LOG.debug("Volume not yet active, retrying %s of %s...", retry, retry_count)
|
||||||
|
time.sleep(2)
|
||||||
|
if volume.status != 'available':
|
||||||
|
raise Exception
|
||||||
|
return volume
|
||||||
|
|
||||||
|
def delete_volumes(self, cinder_client, volumes):
|
||||||
|
if isinstance(volumes, str):
|
||||||
|
volumes = [volumes]
|
||||||
|
for volume in volumes:
|
||||||
|
LOG.info('Deleting volume: {}'.format(volume.name))
|
||||||
|
cinder_client.volumes.delete(volume)
|
||||||
|
|
||||||
|
def find_volumes(self, cinder_client, volume_name):
|
||||||
|
res_vol = []
|
||||||
|
try:
|
||||||
|
req_vols = cinder_client.volumes.list()
|
||||||
|
for vol in req_vols:
|
||||||
|
if volume_name in vol.name:
|
||||||
|
res_vol.append(vol)
|
||||||
|
return res_vol
|
||||||
|
except (cinder_exception.NotFound, keystoneauth1.exceptions.http.NotFound):
|
||||||
|
pass
|
||||||
|
return None
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
# This is a template host access that will be used for all instances
|
# This is a template host access that will be used for all instances
|
||||||
# (the only specific field specific to each instance is the host IP)
|
# (the only specific field specific to each instance is the host IP)
|
||||||
@ -208,9 +257,16 @@ class VmtpTest(object):
|
|||||||
nova_client = novaclient.Client('2', session=sess)
|
nova_client = novaclient.Client('2', session=sess)
|
||||||
neutron = neutronclient.Client('2.0', session=sess)
|
neutron = neutronclient.Client('2.0', session=sess)
|
||||||
self.glance_client = glanceclient.Client('2', session=sess)
|
self.glance_client = glanceclient.Client('2', session=sess)
|
||||||
|
self.cinder_client = cinderclient.Client('2', session=sess) \
|
||||||
|
if self.config.volume else None
|
||||||
|
|
||||||
self.comp = compute.Compute(nova_client, neutron, self.config)
|
self.comp = compute.Compute(nova_client, neutron, self.config)
|
||||||
|
|
||||||
|
if self.config.volume:
|
||||||
|
volumes = self.find_volumes(self.cinder_client, self.config.image_name)
|
||||||
|
if volumes:
|
||||||
|
LOG.info("Removing old VMTP volumes: {}".format(volumes))
|
||||||
|
self.delete_volumes(self.cinder_client, volumes)
|
||||||
# Add the appropriate public key to openstack
|
# Add the appropriate public key to openstack
|
||||||
self.comp.init_key_pair(self.config.public_key_name, self.instance_access)
|
self.comp.init_key_pair(self.config.public_key_name, self.instance_access)
|
||||||
|
|
||||||
@ -295,6 +351,7 @@ class VmtpTest(object):
|
|||||||
# avail_list = self.comp.list_hypervisor(config.availability_zone)
|
# avail_list = self.comp.list_hypervisor(config.availability_zone)
|
||||||
avail_list = self.comp.get_az_host_list()
|
avail_list = self.comp.get_az_host_list()
|
||||||
if not avail_list:
|
if not avail_list:
|
||||||
|
self.teardown()
|
||||||
sys.exit(5)
|
sys.exit(5)
|
||||||
|
|
||||||
# compute the list of client vm placements to run
|
# compute the list of client vm placements to run
|
||||||
@ -452,6 +509,11 @@ class VmtpTest(object):
|
|||||||
if not self.config.reuse_existing_vm and self.net:
|
if not self.config.reuse_existing_vm and self.net:
|
||||||
self.net.dispose()
|
self.net.dispose()
|
||||||
# Remove the public key
|
# Remove the public key
|
||||||
|
if self.config.volume:
|
||||||
|
volumes = self.find_volumes(self.cinder_client, self.config.image_name)
|
||||||
|
if volumes:
|
||||||
|
LOG.info("Removing VMTP volumes: {}".format(volumes))
|
||||||
|
self.delete_volumes(self.cinder_client, volumes)
|
||||||
if self.comp:
|
if self.comp:
|
||||||
self.comp.remove_public_key(self.config.public_key_name)
|
self.comp.remove_public_key(self.config.public_key_name)
|
||||||
# Finally remove the security group
|
# Finally remove the security group
|
||||||
@ -619,7 +681,7 @@ def gen_report_data(proto, result):
|
|||||||
if proto in ['TCP', 'Upload', 'Download']:
|
if proto in ['TCP', 'Upload', 'Download']:
|
||||||
for key in list(retval.keys()):
|
for key in list(retval.keys()):
|
||||||
if retval[key]:
|
if retval[key]:
|
||||||
retval[key] = '{0:n}'.format(retval[key] / tcp_test_count)
|
retval[key] = '{0:n}'.format(int(retval[key] / tcp_test_count))
|
||||||
else:
|
else:
|
||||||
retval.pop(key)
|
retval.pop(key)
|
||||||
|
|
||||||
@ -969,6 +1031,12 @@ def parse_opts_from_cli():
|
|||||||
help='Filename for saving VMTP logs',
|
help='Filename for saving VMTP logs',
|
||||||
metavar='<log_file>')
|
metavar='<log_file>')
|
||||||
|
|
||||||
|
parser.add_argument('--volume', dest='volume',
|
||||||
|
default=None,
|
||||||
|
action='store',
|
||||||
|
help='create bootable volumes for instances',
|
||||||
|
metavar='<volume>')
|
||||||
|
|
||||||
return parser.parse_known_args()[0]
|
return parser.parse_known_args()[0]
|
||||||
|
|
||||||
|
|
||||||
@ -1012,6 +1080,7 @@ def merge_opts_to_configs(opts):
|
|||||||
config.keep_first_flow_and_exit = opts.keep_first_flow_and_exit
|
config.keep_first_flow_and_exit = opts.keep_first_flow_and_exit
|
||||||
config.inter_node_only = opts.inter_node_only
|
config.inter_node_only = opts.inter_node_only
|
||||||
config.same_network_only = opts.same_network_only
|
config.same_network_only = opts.same_network_only
|
||||||
|
config.volume = opts.volume
|
||||||
|
|
||||||
if config.public_key_file and not os.path.isfile(config.public_key_file):
|
if config.public_key_file and not os.path.isfile(config.public_key_file):
|
||||||
LOG.warning('Invalid public_key_file:' + config.public_key_file)
|
LOG.warning('Invalid public_key_file:' + config.public_key_file)
|
||||||
|
Loading…
Reference in New Issue
Block a user