script for validation of a vpshere's configuration is added
Change-Id: I21ad2591f0300adf5d8554cd59f54046c00fcbf5
This commit is contained in:
parent
fd04abd7bc
commit
f286c0bdc2
679
plugin_test/utils/jenkins/victl.py
Normal file
679
plugin_test/utils/jenkins/victl.py
Normal file
@ -0,0 +1,679 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Copyright 2016 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
|
||||
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 argparse
|
||||
import atexit
|
||||
import logging as log
|
||||
import ssl
|
||||
import sys
|
||||
import textwrap
|
||||
|
||||
from os import environ
|
||||
|
||||
import paramiko
|
||||
|
||||
from pyVim import connect
|
||||
|
||||
from pyVmomi import vim
|
||||
from pyVmomi import vmodl
|
||||
|
||||
import requests
|
||||
|
||||
requests.packages.urllib3.disable_warnings()
|
||||
log.getLogger("requests").setLevel(log.WARNING)
|
||||
log.basicConfig(format='%(message)s', level=log.INFO) # %(levelname)s:
|
||||
|
||||
|
||||
class NotFoundException(Exception):
|
||||
"""Raise when some object cannot be found."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class Victl(object):
|
||||
"""VMware base actions."""
|
||||
|
||||
_service_instance = None
|
||||
content = None
|
||||
|
||||
def __init__(self, host, user, password, port):
|
||||
"""Create ssl context."""
|
||||
try:
|
||||
# workaround https://github.com/vmware/pyvmomi/issues/235
|
||||
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
|
||||
context.verify_mode = ssl.CERT_NONE
|
||||
self._service_instance = connect.SmartConnect(host=host,
|
||||
user=user,
|
||||
pwd=password,
|
||||
port=int(port),
|
||||
sslContext=context)
|
||||
|
||||
if not self._service_instance:
|
||||
raise Exception('Could not connect to the specified host using'
|
||||
' specified username and password')
|
||||
|
||||
atexit.register(connect.Disconnect, self._service_instance)
|
||||
|
||||
self.content = self._service_instance.RetrieveContent()
|
||||
|
||||
except vmodl.MethodFault as e:
|
||||
raise Exception('Caught vmodl fault: ' + e.msg)
|
||||
|
||||
def get_dc_object(self, datacenter):
|
||||
"""Return datacenter object with specified name."""
|
||||
for dc in self.content.rootFolder.childEntity:
|
||||
if dc.name == datacenter:
|
||||
return dc
|
||||
|
||||
raise NotFoundException("Can not find dc "
|
||||
"'{dc_name}'".format(dc_name=datacenter))
|
||||
|
||||
def get_cluster_hosts(self, dc, cluster):
|
||||
"""Return list of hosts names in specified cluster."""
|
||||
host_folder = dc.hostFolder
|
||||
for _cluster in host_folder.childEntity:
|
||||
if _cluster.name == cluster:
|
||||
return [host.name for host in _cluster.host]
|
||||
|
||||
raise Exception("Cluster '{cl_name}' is empty".format(cl_name=cluster))
|
||||
|
||||
def get_cluster_hosts_objects(self, dc, cluster):
|
||||
"""Return list of hosts names in specified cluster."""
|
||||
host_folder = dc.hostFolder
|
||||
for _cluster in host_folder.childEntity:
|
||||
if _cluster.name == cluster:
|
||||
return _cluster.host
|
||||
|
||||
def get_vds_object(self, dc, vds):
|
||||
"""Return dvSwitch object with specified name."""
|
||||
network_folder = dc.networkFolder
|
||||
for net in network_folder.childEntity:
|
||||
if isinstance(net, vim.DistributedVirtualSwitch):
|
||||
if net.name == vds:
|
||||
return net
|
||||
|
||||
raise NotFoundException("dvSwitch '{vds}' not found".format(vds=vds))
|
||||
|
||||
def get_vds_hosts(self, datacenter, vdswitch):
|
||||
"""Return list of hosts names in specified dvSwitch."""
|
||||
dc = self.get_dc_object(datacenter)
|
||||
vds = inst.get_vds_object(dc, vdswitch)
|
||||
return [host.config.host.name for host in vds.config.host]
|
||||
|
||||
def get_nics_for_hosts_in_vds(self, hosts, vds):
|
||||
"""Return list of nics for specified hosts in dvSwitch."""
|
||||
nics = []
|
||||
for host in vds.config.host:
|
||||
if host.config.host.name in hosts:
|
||||
nics.append([nic.pnicDevice for nic
|
||||
in host.config.backing.pnicSpec])
|
||||
|
||||
return nics
|
||||
|
||||
def get_clusters(self, datacenter):
|
||||
"""Return list of clusters names in specified datacenter."""
|
||||
dc = self.get_dc_object(datacenter)
|
||||
host_folder = dc.hostFolder
|
||||
return [cluster.name for cluster in host_folder.childEntity]
|
||||
|
||||
def _exec_command(self, host, user, password, cmd):
|
||||
"""Execute command remotely and return output."""
|
||||
client = paramiko.SSHClient()
|
||||
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
try:
|
||||
client.connect(host, username=user, password=password, timeout=3)
|
||||
stdin, stdout, stderr = client.exec_command(cmd)
|
||||
out = stdout.read()
|
||||
except TypeError:
|
||||
raise Exception('There are no valid connections')
|
||||
finally:
|
||||
if client:
|
||||
client.close()
|
||||
return out
|
||||
|
||||
def check_netcpad(self, host, user, password, print_error=False):
|
||||
"""Check up whether connection with nsxv controller is established."""
|
||||
cmd = r"esxcli network ip connection list | grep tcp | grep 1234 | " \
|
||||
r"grep ESTABLISHED"
|
||||
out = self._exec_command(host, user, password, cmd)
|
||||
if not out:
|
||||
if print_error:
|
||||
raise Exception("Host '{host}' not connected to nsxv "
|
||||
"controller".format(host=host))
|
||||
return False
|
||||
return True
|
||||
|
||||
def restart_netcpad(self, host, user, password):
|
||||
"""Restart netcpad."""
|
||||
log.info("Host '{host}', try restart netcpad".format(host=host))
|
||||
|
||||
cmd = r"/etc/init.d/netcpad restart"
|
||||
self._exec_command(host, user, password, cmd)
|
||||
|
||||
def check_portgroup_configured(self, datacenter, cluster, portgroup):
|
||||
"""Check up whether portgroup is configured."""
|
||||
err = ''
|
||||
dc = self.get_dc_object(datacenter)
|
||||
hosts = self.get_cluster_hosts_objects(dc, cluster)
|
||||
for esxi in hosts:
|
||||
if portgroup not in [pg.name for pg in esxi.network]:
|
||||
err += "On esxi '{esxi}' portgroup '{portgr}' "\
|
||||
"not found".format(esxi=esxi.name,
|
||||
portgr=portgroup)
|
||||
if err:
|
||||
raise NotFoundException(err)
|
||||
return True
|
||||
|
||||
def check_storage_configured(self, datacenter, cluster, datastore):
|
||||
"""Check up whether datastore is configured on cluster."""
|
||||
dc = self.get_dc_object(datacenter)
|
||||
hosts = self.get_cluster_hosts_objects(dc, cluster)
|
||||
|
||||
err = {}
|
||||
|
||||
for esxi in hosts:
|
||||
for ds in esxi.datastore:
|
||||
if ds.name == datastore:
|
||||
break
|
||||
else:
|
||||
log.error('ERROR: On esxi "{esxi}" datastore "{ds}" is not '
|
||||
'found'.format(esxi=esxi.name, ds=datastore))
|
||||
err[0] = 'Some datastores not found'
|
||||
continue
|
||||
|
||||
for attached_host in ds.host:
|
||||
if attached_host.key == esxi:
|
||||
break
|
||||
|
||||
if attached_host.mountInfo.mounted:
|
||||
log.info('On esxi "{esxi}" datastore "{ds}" is mounted'
|
||||
''.format(ds=ds.name, esxi=esxi.name))
|
||||
else:
|
||||
log.error('ERROR: On esxi "{esxi}" datastore "{ds}" is NOT '
|
||||
'mounted'.format(ds=ds.name, esxi=esxi.name))
|
||||
err[1] = 'Some datastores not mounted'
|
||||
|
||||
if attached_host.mountInfo.accessible:
|
||||
log.info('On esxi "{esxi}" datastore "{ds}" is accessible'
|
||||
''.format(ds=ds.name, esxi=esxi.name))
|
||||
else:
|
||||
log.error('ERROR: On esxi "{esxi}" datastore "{ds}" is NOT '
|
||||
'accessible'.format(ds=ds.name, esxi=esxi.name))
|
||||
err[2] = 'Some datastores not accessible'
|
||||
|
||||
if err:
|
||||
raise NotFoundException('. '.join(err.values()))
|
||||
|
||||
return True
|
||||
|
||||
def write_test_datastore(self, datacenter, datastore, host):
|
||||
"""Put the file with test data to specified datastore."""
|
||||
dc = self.get_dc_object(datacenter)
|
||||
if datastore not in [ds.name for ds in dc.datastore]:
|
||||
raise NotFoundException("Datastore '{ds}' not found on '{dc}' "
|
||||
"datacenter".format(ds=datastore,
|
||||
dc=datacenter))
|
||||
|
||||
# Build the url to put the file - https://hostname:port/resource?params
|
||||
resource = '/folder/test_upload'
|
||||
params = {'dsName': datastore, 'dcPath': datacenter}
|
||||
http_url = 'https://{vcenter}:443{resource}'.format(vcenter=host,
|
||||
resource=resource)
|
||||
|
||||
# Get the cookie built from the current session
|
||||
client_cookie = self._service_instance._stub.cookie
|
||||
# Break apart the cookie into it's component parts - This is more than
|
||||
# is needed, but a good example of how to break apart the cookie
|
||||
# anyways. The verbosity makes it clear what is happening.
|
||||
cookie_name = client_cookie.split('=', 1)[0]
|
||||
_path_etc = client_cookie.split('=', 1)[1]
|
||||
cookie_value = _path_etc.split(';', 1)[0]
|
||||
cookie_path = _path_etc.split(';', 1)[1].split(';', 1)[0].lstrip()
|
||||
cookie_text = " {value}; ${path}".format(value=cookie_value,
|
||||
path=cookie_path)
|
||||
# Make a cookie
|
||||
cookie = dict()
|
||||
cookie[cookie_name] = cookie_text
|
||||
|
||||
# Get the request headers set up
|
||||
headers = {'Content-Type': 'application/octet-stream'}
|
||||
|
||||
# Get the file to upload ready, extra protection by using with against
|
||||
# leaving open threads
|
||||
# Connect and upload the file
|
||||
request = requests.put(http_url,
|
||||
params=params,
|
||||
data='Test upload file',
|
||||
headers=headers,
|
||||
cookies=cookie,
|
||||
verify=False)
|
||||
if not request.ok:
|
||||
raise Exception("Can not write test file to datastore "
|
||||
"'{ds}'".format(ds=datastore))
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def cluster_list(args, inst):
|
||||
"""Print list of clusters."""
|
||||
clusters = inst.get_clusters(args.datacenter)
|
||||
for cluster in clusters:
|
||||
log.info(cluster)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def check_dvs_attached(args, inst):
|
||||
"""Return 0 if dvs is attached to hosts."""
|
||||
dc = inst.get_dc_object(args.datacenter)
|
||||
vds = inst.get_vds_object(dc, args.vdswitch)
|
||||
hosts_in_cluster = inst.get_cluster_hosts(dc, args.cluster)
|
||||
hosts_in_vds = inst.get_vds_hosts(args.datacenter, args.vdswitch)
|
||||
|
||||
# Check up whether all cluster hosts are in dvSwitch
|
||||
host_not_in_vds = set(hosts_in_cluster) - set(hosts_in_vds)
|
||||
if host_not_in_vds:
|
||||
err = "In cluster '{cl_name}' on dvSwitch '{vds}' not found " \
|
||||
"hosts:".format(cl_name=args.cluster, vds=args.vdswitch)
|
||||
for host in host_not_in_vds:
|
||||
err += "\n {host}".format(host=host)
|
||||
raise NotFoundException(err)
|
||||
|
||||
# Check up whether all cluster hosts have vmnic attached
|
||||
nics = inst.get_nics_for_hosts_in_vds(hosts_in_cluster, vds)
|
||||
for hostname, host_nics in zip(hosts_in_cluster, nics):
|
||||
if args.vmnic not in host_nics:
|
||||
raise Exception("Host '{host}' has not attached nic '{nic}' to "
|
||||
"dvSwitch '{vds}'".format(host=hostname,
|
||||
nic=args.vmnic,
|
||||
vds=vds.name))
|
||||
extra_nic = set(host_nics) - {args.vmnic}
|
||||
if extra_nic:
|
||||
log.info("Host '{host}' has extra nic '{nic}' attached to "
|
||||
"dvSwitch '{vds}'".format(host=hostname,
|
||||
nic=','.join(extra_nic),
|
||||
vds=vds.name))
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def check_esxi(args, inst):
|
||||
"""Return 0 if esxi is connected to controller."""
|
||||
dc = inst.get_dc_object(args.datacenter)
|
||||
hosts_in_cluster = inst.get_cluster_hosts(dc, args.cluster)
|
||||
|
||||
# Check up whether esxi is connected to controller
|
||||
for host in hosts_in_cluster:
|
||||
if not inst.check_netcpad(host, args.user, args.password):
|
||||
inst.restart_netcpad(host, args.user, args.password)
|
||||
|
||||
if inst.check_netcpad(host, args.user, args.password, True):
|
||||
log.info('Host {host} reconnected to nsxv '
|
||||
'controller'.format(host=host))
|
||||
else:
|
||||
log.info('Host {host} NOT reconnected to nsxv '
|
||||
'controller'.format(host=host))
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def check_portgroup(args, inst):
|
||||
"""Return 0 if portgroup is configured on cluster."""
|
||||
if inst.check_portgroup_configured(args.datacenter, args.cluster,
|
||||
args.portgroup):
|
||||
return 0
|
||||
|
||||
|
||||
def check_datastore(args, inst):
|
||||
"""Return 0 if datastore is configured on cluster."""
|
||||
inst.write_test_datastore(args.datacenter, args.datastore, args.host)
|
||||
if inst.check_storage_configured(args.datacenter, args.cluster,
|
||||
args.datastore):
|
||||
return 0
|
||||
|
||||
|
||||
def datastore_list(args, inst):
|
||||
"""Print list of datastores."""
|
||||
dc = inst.get_dc_object(args.datacenter)
|
||||
hosts = inst.get_cluster_hosts_objects(dc, args.cluster)
|
||||
log.info("In cluster '{cl_name}'".format(cl_name=args.cluster))
|
||||
|
||||
for esxi in hosts:
|
||||
log.info(" On esxi '{esxi}' datastores:".format(esxi=esxi.name))
|
||||
|
||||
for ds in esxi.datastore:
|
||||
log.info(" '{ds}'".format(ds=ds.name))
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
_script_name = sys.argv[0] # is used for help message
|
||||
|
||||
# settings for help message formatting
|
||||
_ft = {
|
||||
't': ' ' * 4, # tab
|
||||
's': '-' * 35 # separator
|
||||
}
|
||||
|
||||
_func_args = {} # information about parameters of functions
|
||||
_env_vars = {} # information about environment variables
|
||||
|
||||
|
||||
def setup_env_var(name):
|
||||
"""Save env variable info to the _env_vars dictionary."""
|
||||
_env_vars[name] = environ.get(name, False)
|
||||
return name
|
||||
|
||||
|
||||
def setup_arg(name, short_flag, help, required=True, default=None,
|
||||
env_var=None, example=None):
|
||||
"""Save parameter info to the _func_args dictionary."""
|
||||
_func_args[name] = {
|
||||
'short_flag': short_flag,
|
||||
'long_flag': name,
|
||||
'required': required,
|
||||
'default': default,
|
||||
'help': help,
|
||||
'env_var': env_var,
|
||||
'example': example,
|
||||
}
|
||||
|
||||
|
||||
v_host = setup_env_var('VCENTER_IP')
|
||||
v_user = setup_env_var('VCENTER_USERNAME')
|
||||
v_passw = setup_env_var('VCENTER_PASSWORD')
|
||||
v_dcenter = setup_env_var('VC_DATACENTER')
|
||||
v_datastore = setup_env_var('VC_DATASTORE')
|
||||
v_cluster = setup_env_var('VC_CLUSTER')
|
||||
|
||||
|
||||
setup_arg(name='host',
|
||||
short_flag='s',
|
||||
help='vSphere service to connect to',
|
||||
env_var=v_host,
|
||||
required=not _env_vars[v_host],
|
||||
default=_env_vars[v_host],
|
||||
example='172.16.0.254')
|
||||
|
||||
setup_arg(name='user',
|
||||
short_flag='u',
|
||||
help='User name to use when connecting to host',
|
||||
env_var=v_user,
|
||||
required=not _env_vars[v_user],
|
||||
default=_env_vars[v_user],
|
||||
example='administrator@vsphere.local')
|
||||
|
||||
setup_arg(name='password',
|
||||
short_flag='p',
|
||||
help='Password to use when connecting to host',
|
||||
env_var=v_passw,
|
||||
required=not _env_vars[v_passw],
|
||||
default=_env_vars[v_passw],
|
||||
example='Qwer!1234')
|
||||
|
||||
setup_arg(name='port',
|
||||
short_flag='o',
|
||||
help='Port to connect on',
|
||||
required=False,
|
||||
default=443)
|
||||
|
||||
setup_arg(name='datacenter',
|
||||
short_flag='d',
|
||||
help='Datacenter, which cluster exists',
|
||||
env_var=v_dcenter,
|
||||
required=False,
|
||||
default=_env_vars[v_dcenter] or 'Datacenter')
|
||||
|
||||
setup_arg(name='cluster',
|
||||
short_flag='c',
|
||||
help='Cluster name, where check vswitch',
|
||||
required=not _env_vars[v_cluster],
|
||||
default=_env_vars[v_cluster],
|
||||
env_var=v_cluster, example='Cluster1')
|
||||
|
||||
setup_arg(name='vdswitch',
|
||||
short_flag='v',
|
||||
help='Distributed virtual switch name, which must be configured on '
|
||||
'all esxi in vcenter cluster',
|
||||
required=False,
|
||||
default='dvSwitch')
|
||||
|
||||
setup_arg(name='vmnic',
|
||||
short_flag='n',
|
||||
help='Network interface, which must be attached to vds',
|
||||
required=True,
|
||||
example='vmnic1')
|
||||
|
||||
setup_arg(name='portgroup',
|
||||
short_flag='g',
|
||||
help='Portgroup name, which must be configured on all esxi in '
|
||||
'vcenter cluster',
|
||||
required=True,
|
||||
example='br100')
|
||||
|
||||
setup_arg(name='datastore',
|
||||
short_flag='ds',
|
||||
help='Datastore, which cluster exists',
|
||||
required=not _env_vars[v_datastore],
|
||||
default=_env_vars[v_datastore],
|
||||
env_var=v_datastore,
|
||||
example='nfs')
|
||||
|
||||
setup_arg(name='suser',
|
||||
short_flag='su',
|
||||
help='User name fot connect via ssh to esxi host',
|
||||
required=False,
|
||||
default='root')
|
||||
|
||||
setup_arg(name='spassword',
|
||||
short_flag='sp',
|
||||
help='Password for connect via ssh to esxi host',
|
||||
required=False,
|
||||
default='swordfish')
|
||||
|
||||
|
||||
_functions = {} # information about functions
|
||||
|
||||
|
||||
def setup_func(name, params, func):
|
||||
"""Save function info to the _functions dictionary."""
|
||||
_functions[name] = {
|
||||
'params': params,
|
||||
'func': func
|
||||
}
|
||||
|
||||
_common_params = ['host', 'port', 'user', 'password', 'datacenter']
|
||||
|
||||
|
||||
setup_func(name='cluster-list',
|
||||
params=_common_params,
|
||||
func=cluster_list)
|
||||
|
||||
setup_func(name='check-dvs-attached',
|
||||
params=_common_params + ['cluster', 'vdswitch', 'vmnic'],
|
||||
func=check_dvs_attached)
|
||||
|
||||
setup_func(name='check-esxi',
|
||||
params=_common_params + ['cluster', 'suser', 'spassword'],
|
||||
func=check_esxi)
|
||||
|
||||
setup_func(name='check-portgroup',
|
||||
params=_common_params + ['cluster', 'portgroup'],
|
||||
func=check_portgroup)
|
||||
|
||||
setup_func(name='check-datastore',
|
||||
params=_common_params + ['cluster', 'datastore'],
|
||||
func=check_datastore)
|
||||
|
||||
setup_func(name='datastore-list',
|
||||
params=_common_params + ['cluster'],
|
||||
func=datastore_list)
|
||||
|
||||
|
||||
def _form_env_help():
|
||||
"""Return message about exported and available env variables."""
|
||||
exported = '\n\n{t}{s}\n' \
|
||||
'{t}You already have environment variables:'.format(**_ft)
|
||||
|
||||
available = '' # supported variables to get them from env
|
||||
|
||||
# length of the longest available env variable name
|
||||
av_var_maxlen = max(map(len, _env_vars)) + 1
|
||||
|
||||
defined = filter(lambda x: _env_vars[x], _env_vars)
|
||||
try:
|
||||
# length of the longest exported env variable name
|
||||
ex_var_mlen = max(map(len, defined)) + 1
|
||||
except ValueError:
|
||||
ex_var_mlen = 0
|
||||
|
||||
for name, value in sorted(_env_vars.items()):
|
||||
if value:
|
||||
# adding info about exported variables
|
||||
exported += '\n{t}{t}{name:<{ln}} = {value}'.format(
|
||||
name=name, value=value, ln=ex_var_mlen, **_ft
|
||||
)
|
||||
|
||||
# corresponding parameter name for env name
|
||||
p_name = filter(lambda x: _func_args[x]['env_var'] == name, _func_args)
|
||||
|
||||
# adding info about variables which user can export
|
||||
available += '{t}{t}{name:<{ln}} --{param}\n'.format(
|
||||
name=name, param=list(p_name)[0], ln=av_var_maxlen, **_ft
|
||||
)
|
||||
|
||||
if not ex_var_mlen:
|
||||
exported = ''
|
||||
|
||||
return exported, available
|
||||
|
||||
_env_vars_msg, _env_available = _form_env_help()
|
||||
|
||||
|
||||
def _form_func_help(func_name, with_env=True):
|
||||
"""Return example of usage for function.
|
||||
|
||||
:param with_env: adds examples for env variables export
|
||||
"""
|
||||
# example of function calling
|
||||
func_call = '{t}{t}{script} {func}'.format(script=_script_name,
|
||||
func=func_name, **_ft)
|
||||
# template for function arguments example
|
||||
arg_example = " {flag} '{example}'"
|
||||
|
||||
msg = '{func_call}'.format(func_call=func_call, **_ft) # usage message
|
||||
|
||||
func_params = _functions[func_name]['params']
|
||||
|
||||
for arg in sorted(func_params):
|
||||
params = _func_args.get(arg, None)
|
||||
# adding all arguments examples
|
||||
msg += arg_example.format(
|
||||
flag='-' + params['short_flag'],
|
||||
example=params['example'] or params['default']
|
||||
)
|
||||
|
||||
if with_env:
|
||||
# example with exported variables
|
||||
msg += '\n{t}{t}{t}or\n'.format(**_ft)
|
||||
|
||||
rest_args = '' # required arguments without env variable
|
||||
|
||||
for arg in sorted(func_params):
|
||||
params = _func_args.get(arg, None)
|
||||
|
||||
if params.get('env_var', False): # if parameter has env variable
|
||||
msg += "{t}{t}export {name}='{value}'\n".format(
|
||||
name=params['env_var'],
|
||||
value=params['example'] or params['default'], **_ft
|
||||
)
|
||||
elif params.get('required', False):
|
||||
rest_args += arg_example.format(
|
||||
flag='-' + params['short_flag'],
|
||||
example=params['example'] or params['default']
|
||||
)
|
||||
msg += func_call + rest_args + _env_vars_msg
|
||||
|
||||
return msg
|
||||
|
||||
|
||||
def _def_parser(func_name):
|
||||
"""Return subparser with func_name and func_args_names parameters."""
|
||||
func_params = _functions[func_name]['params']
|
||||
|
||||
help_msg = '{t}{s}\n' \
|
||||
'{t}Examples of usage:\n' \
|
||||
'{func_call}'.\
|
||||
format(func_call=_form_func_help(func_name), **_ft)
|
||||
|
||||
sub_parser = _subparser.add_parser(
|
||||
func_name, formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog=textwrap.indent(help_msg, '')
|
||||
)
|
||||
|
||||
for arg in sorted(func_params):
|
||||
params = _func_args.get(arg, None)
|
||||
sub_parser.add_argument('-{flag}'.format(flag=params['short_flag']),
|
||||
'--{flag}'.format(flag=params['long_flag']),
|
||||
required=params.get('required', True),
|
||||
default=params['default'],
|
||||
help=params['help'])
|
||||
|
||||
sub_parser.set_defaults(func=_functions[func_name]['func'])
|
||||
|
||||
return sub_parser
|
||||
|
||||
|
||||
def _form_help_msg():
|
||||
"""Return usage message for the program."""
|
||||
msg = '\n{t}{s}\n' \
|
||||
'{t}You can use these environment variables:\n' \
|
||||
'{vars}\n' \
|
||||
'{t}{s}\n' \
|
||||
'{t}Examples of usage:\n'.format(vars=_env_available, **_ft)
|
||||
|
||||
for func in sorted(_functions):
|
||||
msg += _form_func_help(func, False) + '\n\n'
|
||||
|
||||
msg += _env_vars_msg
|
||||
|
||||
return msg
|
||||
|
||||
|
||||
_parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog=textwrap.indent(_form_help_msg(), '')
|
||||
)
|
||||
_subparser = _parser.add_subparsers()
|
||||
|
||||
for _func in _functions:
|
||||
_def_parser(_func)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
args = _parser.parse_args()
|
||||
if len(sys.argv) == 1:
|
||||
_parser.print_help()
|
||||
sys.exit(0)
|
||||
|
||||
try:
|
||||
inst = Victl(args.host, args.user, args.password, args.port)
|
||||
res = args.func(args, inst)
|
||||
except Exception as e:
|
||||
log.error('ERROR: {msg}'.format(msg=e))
|
||||
res = 1
|
||||
|
||||
sys.exit(res)
|
Loading…
Reference in New Issue
Block a user