Improve logging and CLI output
Logging was incomplete, and unhelpful in case of an exception. Add also a log_file parameter to the configuration file, so that CLI actions can be logged to a file for audit. Change-Id: Ifa7a2f2828fa38be8879a4a9c64fe948b95d5fb8
This commit is contained in:
parent
110a460dd2
commit
971b64deaa
@ -13,3 +13,6 @@ url=https://example.com/zuul/
|
|||||||
tenant=mytenant
|
tenant=mytenant
|
||||||
# verify_ssl=False
|
# verify_ssl=False
|
||||||
auth_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
|
auth_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
|
||||||
|
# the path must be writable by the user.
|
||||||
|
log_file=/path/to/log
|
||||||
|
log_level=DEBUG
|
@ -99,6 +99,12 @@ class ZuulClient():
|
|||||||
def parseArguments(self, args=None):
|
def parseArguments(self, args=None):
|
||||||
self.parser = self.createParser()
|
self.parser = self.createParser()
|
||||||
self.args = self.parser.parse_args(args)
|
self.args = self.parser.parse_args(args)
|
||||||
|
if (
|
||||||
|
(self.args.zuul_url and self.args.zuul_config) or
|
||||||
|
(not self.args.zuul_url and not self.args.zuul_config)
|
||||||
|
):
|
||||||
|
raise ArgumentException(
|
||||||
|
'Either specify --zuul-url or use a config file')
|
||||||
if not getattr(self.args, 'func', None):
|
if not getattr(self.args, 'func', None):
|
||||||
self.parser.print_help()
|
self.parser.print_help()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@ -139,9 +145,31 @@ class ZuulClient():
|
|||||||
"Unable to locate config file in %s" % locations)
|
"Unable to locate config file in %s" % locations)
|
||||||
|
|
||||||
def setup_logging(self):
|
def setup_logging(self):
|
||||||
"""Client logging does not rely on conf file"""
|
config_args = dict(
|
||||||
|
format='%(levelname)-8s - %(message)s'
|
||||||
|
)
|
||||||
if self.args.verbose:
|
if self.args.verbose:
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
config_args['level'] = logging.DEBUG
|
||||||
|
else:
|
||||||
|
config_args['level'] = logging.ERROR
|
||||||
|
# set logging across all components (urllib etc)
|
||||||
|
logging.basicConfig(**config_args)
|
||||||
|
if self.args.zuul_config and\
|
||||||
|
self.args.zuul_config in self.config.sections():
|
||||||
|
zuul_conf = self.args.zuul_config
|
||||||
|
log_file = get_default(self.config,
|
||||||
|
zuul_conf, 'log_file', None)
|
||||||
|
if log_file is not None:
|
||||||
|
fh = logging.FileHandler(log_file)
|
||||||
|
f_loglevel = get_default(self.config,
|
||||||
|
zuul_conf, 'log_level', 'INFO')
|
||||||
|
fh.setLevel(getattr(logging, f_loglevel, 'INFO'))
|
||||||
|
f_formatter = logging.Formatter(
|
||||||
|
fmt='%(asctime)s %(name)s %(levelname)-8s - %(message)s',
|
||||||
|
datefmt='%x %X'
|
||||||
|
)
|
||||||
|
fh.setFormatter(f_formatter)
|
||||||
|
self.log.addHandler(fh)
|
||||||
|
|
||||||
def _main(self, args=None):
|
def _main(self, args=None):
|
||||||
# TODO make func return specific return codes
|
# TODO make func return specific return codes
|
||||||
@ -161,15 +189,21 @@ class ZuulClient():
|
|||||||
print()
|
print()
|
||||||
raise
|
raise
|
||||||
if ret:
|
if ret:
|
||||||
|
self.log.info('Command %s completed '
|
||||||
|
'successfully' % self.args.func.__name__)
|
||||||
return 0
|
return 0
|
||||||
else:
|
else:
|
||||||
|
self.log.error('Command %s completed '
|
||||||
|
'with error(s)' % self.args.func.__name__)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def main(self):
|
def main(self):
|
||||||
try:
|
try:
|
||||||
sys.exit(self._main())
|
sys.exit(self._main())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log.error(e)
|
self.log.exception(
|
||||||
|
'Failed with the following exception: %s ' % e
|
||||||
|
)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def _check_tenant_scope(self, client):
|
def _check_tenant_scope(self, client):
|
||||||
@ -225,7 +259,7 @@ class ZuulClient():
|
|||||||
node_hold_expiration = self.args.node_hold_expiration
|
node_hold_expiration = self.args.node_hold_expiration
|
||||||
client = self.get_client()
|
client = self.get_client()
|
||||||
self._check_tenant_scope(client)
|
self._check_tenant_scope(client)
|
||||||
r = client.autohold(
|
kwargs = dict(
|
||||||
tenant=self.tenant(),
|
tenant=self.tenant(),
|
||||||
project=self.args.project,
|
project=self.args.project,
|
||||||
job=self.args.job,
|
job=self.args.job,
|
||||||
@ -234,6 +268,8 @@ class ZuulClient():
|
|||||||
reason=self.args.reason,
|
reason=self.args.reason,
|
||||||
count=self.args.count,
|
count=self.args.count,
|
||||||
node_hold_expiration=node_hold_expiration)
|
node_hold_expiration=node_hold_expiration)
|
||||||
|
self.log.info('Invoking autohold with arguments: %s' % kwargs)
|
||||||
|
r = client.autohold(**kwargs)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def add_autohold_delete_subparser(self, subparsers):
|
def add_autohold_delete_subparser(self, subparsers):
|
||||||
@ -249,7 +285,12 @@ class ZuulClient():
|
|||||||
def autohold_delete(self):
|
def autohold_delete(self):
|
||||||
client = self.get_client()
|
client = self.get_client()
|
||||||
self._check_tenant_scope(client)
|
self._check_tenant_scope(client)
|
||||||
return client.autohold_delete(self.args.id, self.tenant())
|
kwargs = dict(
|
||||||
|
id=self.args.id,
|
||||||
|
tenant=self.tenant()
|
||||||
|
)
|
||||||
|
self.log.info('Invoking autohold-delete with arguments: %s' % kwargs)
|
||||||
|
return client.autohold_delete(**kwargs)
|
||||||
|
|
||||||
def add_autohold_info_subparser(self, subparsers):
|
def add_autohold_info_subparser(self, subparsers):
|
||||||
cmd_autohold_info = subparsers.add_parser(
|
cmd_autohold_info = subparsers.add_parser(
|
||||||
@ -337,11 +378,14 @@ class ZuulClient():
|
|||||||
def enqueue(self):
|
def enqueue(self):
|
||||||
client = self.get_client()
|
client = self.get_client()
|
||||||
self._check_tenant_scope(client)
|
self._check_tenant_scope(client)
|
||||||
r = client.enqueue(
|
kwargs = dict(
|
||||||
tenant=self.tenant(),
|
tenant=self.tenant(),
|
||||||
pipeline=self.args.pipeline,
|
pipeline=self.args.pipeline,
|
||||||
project=self.args.project,
|
project=self.args.project,
|
||||||
change=self.args.change)
|
change=self.args.change
|
||||||
|
)
|
||||||
|
self.log.info('Invoking enqueue with arguments: %s' % kwargs)
|
||||||
|
r = client.enqueue(**kwargs)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def add_enqueue_ref_subparser(self, subparsers):
|
def add_enqueue_ref_subparser(self, subparsers):
|
||||||
@ -372,13 +416,16 @@ class ZuulClient():
|
|||||||
def enqueue_ref(self):
|
def enqueue_ref(self):
|
||||||
client = self.get_client()
|
client = self.get_client()
|
||||||
self._check_tenant_scope(client)
|
self._check_tenant_scope(client)
|
||||||
r = client.enqueue_ref(
|
kwargs = dict(
|
||||||
tenant=self.tenant(),
|
tenant=self.tenant(),
|
||||||
pipeline=self.args.pipeline,
|
pipeline=self.args.pipeline,
|
||||||
project=self.args.project,
|
project=self.args.project,
|
||||||
ref=self.args.ref,
|
ref=self.args.ref,
|
||||||
oldrev=self.args.oldrev,
|
oldrev=self.args.oldrev,
|
||||||
newrev=self.args.newrev)
|
newrev=self.args.newrev
|
||||||
|
)
|
||||||
|
self.log.info('Invoking enqueue-ref with arguments: %s' % kwargs)
|
||||||
|
r = client.enqueue_ref(**kwargs)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def add_dequeue_subparser(self, subparsers):
|
def add_dequeue_subparser(self, subparsers):
|
||||||
@ -401,12 +448,15 @@ class ZuulClient():
|
|||||||
def dequeue(self):
|
def dequeue(self):
|
||||||
client = self.get_client()
|
client = self.get_client()
|
||||||
self._check_tenant_scope(client)
|
self._check_tenant_scope(client)
|
||||||
r = client.dequeue(
|
kwargs = dict(
|
||||||
tenant=self.tenant(),
|
tenant=self.tenant(),
|
||||||
pipeline=self.args.pipeline,
|
pipeline=self.args.pipeline,
|
||||||
project=self.args.project,
|
project=self.args.project,
|
||||||
change=self.args.change,
|
change=self.args.change,
|
||||||
ref=self.args.ref)
|
ref=self.args.ref
|
||||||
|
)
|
||||||
|
self.log.info('Invoking dequeue with arguments: %s' % kwargs)
|
||||||
|
r = client.dequeue(**kwargs)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def add_promote_subparser(self, subparsers):
|
def add_promote_subparser(self, subparsers):
|
||||||
@ -424,15 +474,16 @@ class ZuulClient():
|
|||||||
def promote(self):
|
def promote(self):
|
||||||
client = self.get_client()
|
client = self.get_client()
|
||||||
self._check_tenant_scope(client)
|
self._check_tenant_scope(client)
|
||||||
r = client.promote(
|
kwargs = dict(
|
||||||
tenant=self.tenant(),
|
tenant=self.tenant(),
|
||||||
pipeline=self.args.pipeline,
|
pipeline=self.args.pipeline,
|
||||||
change_ids=self.args.changes)
|
change_ids=self.args.changes
|
||||||
|
)
|
||||||
|
self.log.info('Invoking promote with arguments: %s' % kwargs)
|
||||||
|
r = client.promote(**kwargs)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def get_client(self):
|
def get_client(self):
|
||||||
if self.args.zuul_url and self.args.zuul_config:
|
|
||||||
raise Exception('Either specify --zuul-url or use a config file')
|
|
||||||
if self.args.zuul_url:
|
if self.args.zuul_url:
|
||||||
self.log.debug(
|
self.log.debug(
|
||||||
'Using Zuul URL provided as argument to instantiate client')
|
'Using Zuul URL provided as argument to instantiate client')
|
||||||
@ -559,7 +610,7 @@ class ZuulClient():
|
|||||||
key = client.get_key(self.tenant(), self.args.project)
|
key = client.get_key(self.tenant(), self.args.project)
|
||||||
pubkey_file.write(str.encode(key))
|
pubkey_file.write(str.encode(key))
|
||||||
pubkey_file.close()
|
pubkey_file.close()
|
||||||
self.log.debug('Calling openssl')
|
self.log.debug('Invoking openssl')
|
||||||
ciphertext_chunks = encrypt_with_openssl(pubkey_file.name,
|
ciphertext_chunks = encrypt_with_openssl(pubkey_file.name,
|
||||||
plaintext,
|
plaintext,
|
||||||
self.log)
|
self.log)
|
||||||
@ -644,7 +695,6 @@ class ZuulClient():
|
|||||||
def builds(self):
|
def builds(self):
|
||||||
if self.args.voting and self.args.non_voting:
|
if self.args.voting and self.args.non_voting:
|
||||||
raise Exception('--voting and --non-voting are mutually exclusive')
|
raise Exception('--voting and --non-voting are mutually exclusive')
|
||||||
self.log.info('Showing the last {} matches.'.format(self.args.limit))
|
|
||||||
filters = {'limit': self.args.limit,
|
filters = {'limit': self.args.limit,
|
||||||
'skip': self.args.skip}
|
'skip': self.args.skip}
|
||||||
if self.args.project:
|
if self.args.project:
|
||||||
|
@ -39,7 +39,7 @@ def get_default(config, section, option, default=None, expand_user=False):
|
|||||||
def encrypt_with_openssl(pubkey_path, plaintext, logger=None):
|
def encrypt_with_openssl(pubkey_path, plaintext, logger=None):
|
||||||
cmd = ['openssl', 'version']
|
cmd = ['openssl', 'version']
|
||||||
if logger:
|
if logger:
|
||||||
logger.debug('calling "%s"' % ' '.join(cmd))
|
logger.debug('Invoking "%s"' % ' '.join(cmd))
|
||||||
try:
|
try:
|
||||||
openssl_version = subprocess.check_output(
|
openssl_version = subprocess.check_output(
|
||||||
cmd).split()[1]
|
cmd).split()[1]
|
||||||
@ -48,7 +48,7 @@ def encrypt_with_openssl(pubkey_path, plaintext, logger=None):
|
|||||||
|
|
||||||
cmd = ['openssl', 'rsa', '-text', '-pubin', '-in', pubkey_path]
|
cmd = ['openssl', 'rsa', '-text', '-pubin', '-in', pubkey_path]
|
||||||
if logger:
|
if logger:
|
||||||
logger.debug('calling "%s"' % ' '.join(cmd))
|
logger.debug('Invoking "%s"' % ' '.join(cmd))
|
||||||
p = subprocess.Popen(cmd,
|
p = subprocess.Popen(cmd,
|
||||||
stdout=subprocess.PIPE)
|
stdout=subprocess.PIPE)
|
||||||
(stdout, stderr) = p.communicate()
|
(stdout, stderr) = p.communicate()
|
||||||
@ -81,7 +81,7 @@ def encrypt_with_openssl(pubkey_path, plaintext, logger=None):
|
|||||||
'-oaep', '-pubin', '-inkey',
|
'-oaep', '-pubin', '-inkey',
|
||||||
pubkey_path]
|
pubkey_path]
|
||||||
if logger:
|
if logger:
|
||||||
logger.debug('calling "%s" with each data chunk:' % ' '.join(cmd))
|
logger.debug('Invoking "%s" with each data chunk:' % ' '.join(cmd))
|
||||||
for count in range(chunks):
|
for count in range(chunks):
|
||||||
chunk = plaintext[int(count * max_bytes):
|
chunk = plaintext[int(count * max_bytes):
|
||||||
int((count + 1) * max_bytes)]
|
int((count + 1) * max_bytes)]
|
||||||
|
Loading…
Reference in New Issue
Block a user