Add support to run VMTP as a library
Change-Id: I6bc95d03bc6f35e2204458ad9f5368f71e424f1b
This commit is contained in:
parent
10e4fdb830
commit
933a64ae57
@ -277,6 +277,24 @@ It is possible to use VMTP to measure throughput for IPv6.
|
||||
Set ipv6_mode to slaac, dhcpv6-stateful or dhcpv6-stateless. If SLAAC or DHCPv6 stateless is enabled make sure to have radvd packaged in as part of openstack install. For DHCPv6 stateful you need dnsmasq version >= 2.68. The test creates 2 networks and creates 1 IPv4 and 1 IPv6 subnet inside each of these networks. The subnets are created based on the IPv6 mode that you set in the configuration file. The Floating IP result case is skipped for IPv6 since there is no concept of a floating ip with IPv6.
|
||||
|
||||
|
||||
Running VMTP as a library
|
||||
-------------------------
|
||||
|
||||
VMTP supports to be invoked from another Python program, just like an API call. Once the benchmarking is finished, the API will return a Python dictionary with all details.
|
||||
|
||||
Example of code for running VMTP as an API call::
|
||||
|
||||
import argparse
|
||||
opts = argparse.Namespace()
|
||||
opts.rc = "<path_to_rc_file>"
|
||||
opts.passwd = "<password_of_the_cloud>"
|
||||
opts.inter_node_only = True
|
||||
opts.json = "my.json"
|
||||
|
||||
import vmtp
|
||||
vmtp.run_vmtp(opts)
|
||||
|
||||
|
||||
Generating charts from JSON results
|
||||
-----------------------------------
|
||||
|
||||
|
152
vmtp/vmtp.py
152
vmtp/vmtp.py
@ -623,51 +623,25 @@ def normalize_paths(cfg):
|
||||
if cfg.private_key_file:
|
||||
cfg.private_key_file = os.path.expanduser(os.path.expanduser(cfg.private_key_file))
|
||||
|
||||
def main():
|
||||
def _get_ssh_access(opt_name, opt_value):
|
||||
'''Allocate a HostSshAccess instance to the option value
|
||||
Check that a password is provided or the key pair in the config file
|
||||
is valid.
|
||||
If invalid exit with proper error message
|
||||
'''
|
||||
if not opt_value:
|
||||
return None
|
||||
def get_ssh_access(opt_name, opt_value, config):
|
||||
'''Allocate a HostSshAccess instance to the option value
|
||||
Check that a password is provided or the key pair in the config file
|
||||
is valid.
|
||||
If invalid exit with proper error message
|
||||
'''
|
||||
if not opt_value:
|
||||
return None
|
||||
|
||||
host_access = sshutils.SSHAccess(opt_value)
|
||||
host_access.private_key_file = config.private_key_file
|
||||
host_access.public_key_file = config.public_key_file
|
||||
if host_access.error:
|
||||
print'Error for --' + (opt_name + ':' + host_access.error)
|
||||
sys.exit(2)
|
||||
return host_access
|
||||
host_access = sshutils.SSHAccess(opt_value)
|
||||
host_access.private_key_file = config.private_key_file
|
||||
host_access.public_key_file = config.public_key_file
|
||||
if host_access.error:
|
||||
print'Error for --' + (opt_name + ':' + host_access.error)
|
||||
sys.exit(2)
|
||||
return host_access
|
||||
|
||||
def _merge_config(cfg_file, source_config, required=False):
|
||||
'''
|
||||
returns the merged config or exits if the file does not exist and is required
|
||||
'''
|
||||
dest_config = source_config
|
||||
|
||||
fullname = os.path.expanduser(cfg_file)
|
||||
if os.path.isfile(fullname):
|
||||
print('Loading ' + fullname + '...')
|
||||
try:
|
||||
alt_config = configure.Configuration.from_file(fullname).configure()
|
||||
dest_config = source_config.merge(alt_config)
|
||||
|
||||
except configure.ConfigurationError:
|
||||
# this is in most cases when the config file passed is empty
|
||||
# configure.ConfigurationError: unconfigured
|
||||
# in case of syntax error, another exception is thrown:
|
||||
# TypeError: string indices must be integers, not str
|
||||
pass
|
||||
elif required:
|
||||
print('Error: configration file %s does not exist' % (fullname))
|
||||
sys.exit(1)
|
||||
return dest_config
|
||||
|
||||
logging.basicConfig()
|
||||
def parse_opts_from_cli():
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument('-c', '--config', dest='config',
|
||||
action='store',
|
||||
help='override default values with a config file',
|
||||
@ -683,7 +657,7 @@ def main():
|
||||
help='Enable CPU monitoring (requires Ganglia)',
|
||||
metavar='<gmond_ip>[:<port>]')
|
||||
|
||||
parser.add_argument('-p', '--password', dest='pwd',
|
||||
parser.add_argument('-p', '--password', dest='passwd',
|
||||
action='store',
|
||||
help='OpenStack password',
|
||||
metavar='<password>')
|
||||
@ -799,11 +773,34 @@ def main():
|
||||
help='The test description to be stored in JSON or MongoDB',
|
||||
metavar='<test_description>')
|
||||
|
||||
return parser.parse_known_args()[0]
|
||||
|
||||
(opts, args) = parser.parse_known_args()
|
||||
def merge_opts_to_configs(opts):
|
||||
def _merge_config(cfg_file, source_config, required=False):
|
||||
'''
|
||||
returns the merged config or exits if the file does not exist and is required
|
||||
'''
|
||||
dest_config = source_config
|
||||
|
||||
fullname = os.path.expanduser(cfg_file)
|
||||
if os.path.isfile(fullname):
|
||||
print('Loading ' + fullname + '...')
|
||||
try:
|
||||
alt_config = configure.Configuration.from_file(fullname).configure()
|
||||
dest_config = source_config.merge(alt_config)
|
||||
|
||||
except configure.ConfigurationError:
|
||||
# this is in most cases when the config file passed is empty
|
||||
# configure.ConfigurationError: unconfigured
|
||||
# in case of syntax error, another exception is thrown:
|
||||
# TypeError: string indices must be integers, not str
|
||||
pass
|
||||
elif required:
|
||||
print('Error: configration file %s does not exist' % (fullname))
|
||||
sys.exit(1)
|
||||
return dest_config
|
||||
|
||||
default_cfg_file = resource_string(__name__, "cfg.default.yaml")
|
||||
|
||||
# read the default configuration file and possibly an override config file
|
||||
# the precedence order is as follows:
|
||||
# $HOME/.vmtp.yaml if exists
|
||||
@ -849,7 +846,7 @@ def main():
|
||||
config.json_file = None
|
||||
|
||||
# Initialize the external host access
|
||||
config.ext_host = _get_ssh_access('external-host', opts.ext_host)
|
||||
config.ext_host = get_ssh_access('external-host', opts.ext_host, config)
|
||||
|
||||
###################################################
|
||||
# VM Image URL
|
||||
@ -945,9 +942,29 @@ def main():
|
||||
else:
|
||||
config.tp_tool = None
|
||||
|
||||
# 3 forms
|
||||
# A list of 0 to 2 HostSshAccess elements
|
||||
return config
|
||||
|
||||
def run_vmtp(opts):
|
||||
'''Run VMTP
|
||||
:param opts: Parameters that to be passed to VMTP in type argparse.Namespace(). See:
|
||||
http://vmtp.readthedocs.org/en/latest/usage.html#running-vmtp-as-a-library
|
||||
for examples of the usage on this API.
|
||||
:return: A dictionary which contains the results in details.
|
||||
'''
|
||||
|
||||
if (sys.argv == ['']):
|
||||
# Running from a Python call
|
||||
def_opts = parse_opts_from_cli()
|
||||
for key, value in vars(def_opts).iteritems():
|
||||
if key not in opts:
|
||||
opts.__setattr__(key, value)
|
||||
|
||||
config = merge_opts_to_configs(opts)
|
||||
|
||||
# Run the natvie host tests if specified by user
|
||||
if opts.hosts:
|
||||
# 3 forms
|
||||
# A list of 0 to 2 HostSshAccess elements
|
||||
native_hosts = []
|
||||
if_name = None
|
||||
for host in opts.hosts:
|
||||
@ -961,23 +978,16 @@ def main():
|
||||
if not if_name and last_arg:
|
||||
if_name = last_arg
|
||||
host = host[:last_column_index]
|
||||
native_hosts.append(_get_ssh_access('host', host))
|
||||
native_hosts.append(get_ssh_access('host', host, config))
|
||||
native_tp_results = test_native_tp(native_hosts, if_name, config)
|
||||
else:
|
||||
native_tp_results = []
|
||||
|
||||
# replace all command line arguments (after the prog name) with
|
||||
# those args that have not been parsed by this parser so that the
|
||||
# unit test parser is not bothered by local arguments
|
||||
sys.argv[1:] = args
|
||||
vmtp_net = None
|
||||
vmtp_instance = None
|
||||
|
||||
cred = credentials.Credentials(opts.rc, opts.pwd, opts.no_env)
|
||||
# Parse the credentials of the OpenStack cloud, and run the benchmarking
|
||||
cred = credentials.Credentials(opts.rc, opts.passwd, opts.no_env)
|
||||
if not cred.rc_auth_url:
|
||||
print 'Error: Cannot read the credentials of the cloud. '
|
||||
sys.exit(1)
|
||||
|
||||
if config.debug:
|
||||
print 'Using ' + cred.rc_auth_url
|
||||
vmtp_instance = VmtpTest(config, cred)
|
||||
@ -988,28 +998,36 @@ def main():
|
||||
|
||||
# Retrieve controller information if requested
|
||||
# controller node ssh access to collect metadata for the run.
|
||||
ctrl_host_access = _get_ssh_access('controller-node', opts.controller_node)
|
||||
ctrl_host_access = get_ssh_access('controller-node', opts.controller_node, config)
|
||||
get_controller_info(ctrl_host_access,
|
||||
vmtp_net,
|
||||
vmtp_instance.rescol,
|
||||
config.ssh_retry_count)
|
||||
|
||||
# Print the report
|
||||
print_report(vmtp_instance.rescol.results)
|
||||
|
||||
# If saving the results to JSON or MongoDB, get additional details:
|
||||
if config.json_file or config.vmtp_mongod_ip:
|
||||
vmtp_instance.rescol.mask_credentials()
|
||||
vmtp_instance.rescol.generate_runid()
|
||||
# Post-processing of the results, adding some metadata
|
||||
vmtp_instance.rescol.add_property('auth_url', cred.rc_auth_url)
|
||||
vmtp_instance.rescol.mask_credentials()
|
||||
vmtp_instance.rescol.generate_runid()
|
||||
if opts.test_description:
|
||||
vmtp_instance.rescol.add_property('test_description', opts.test_description)
|
||||
|
||||
# Save results to a JSON file
|
||||
if config.json_file:
|
||||
# Test Description
|
||||
if opts.test_description:
|
||||
vmtp_instance.rescol.add_property('test_description', opts.test_description)
|
||||
vmtp_instance.rescol.add_property('auth_url', cred.rc_auth_url)
|
||||
vmtp_instance.rescol.save(config)
|
||||
|
||||
# Save results to MongoDB
|
||||
if config.vmtp_mongod_ip:
|
||||
vmtp_instance.rescol.save_to_db(config)
|
||||
|
||||
return vmtp_instance.rescol.results
|
||||
|
||||
def main():
|
||||
logging.basicConfig()
|
||||
opts = parse_opts_from_cli()
|
||||
run_vmtp(opts)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
Loading…
x
Reference in New Issue
Block a user