Support adding API keys to client configs

Sets the groundwork for the remainder of #65
This commit is contained in:
Joshua Boniface 2020-01-08 18:36:31 -05:00
parent c26ee544a9
commit 10d892c698
1 changed files with 42 additions and 12 deletions

View File

@ -24,6 +24,7 @@ import socket
import click import click
import tempfile import tempfile
import os import os
import stat
import subprocess import subprocess
import difflib import difflib
import re import re
@ -63,7 +64,12 @@ def read_from_yaml(cfgfile):
scheme = 'https' scheme = 'https'
else: else:
scheme = 'http' scheme = 'http'
return host, port, scheme if strtobool(api_config['pvc']['api']['authentication']['enabled']):
# Always use the first token
api_key = api_config['pvc']['api']['authentication']['tokens'][0]['token']
else:
api_key = 'N/A'
return host, port, scheme, api_key
def get_config(store_data, cluster=None): def get_config(store_data, cluster=None):
# This is generally static # This is generally static
@ -79,7 +85,7 @@ def get_config(store_data, cluster=None):
# This is a reference to an API configuration; grab the details from its listen address # This is a reference to an API configuration; grab the details from its listen address
cfgfile = cluster_details.get('cfgfile') cfgfile = cluster_details.get('cfgfile')
if os.path.isfile(cfgfile): if os.path.isfile(cfgfile):
host, port, scheme = read_from_yaml(cfgfile) host, port, scheme, api_key = read_from_yaml(cfgfile)
else: else:
return { 'badcfg': True } return { 'badcfg': True }
else: else:
@ -87,12 +93,14 @@ def get_config(store_data, cluster=None):
host = cluster_details['host'] host = cluster_details['host']
port = cluster_details['port'] port = cluster_details['port']
scheme = cluster_details['scheme'] scheme = cluster_details['scheme']
api_key = cluster_details['api_key']
config = dict() config = dict()
config['debug'] = False config['debug'] = False
config['cluster'] = cluster config['cluster'] = cluster
config['api_host'] = '{}:{}'.format(host, port) config['api_host'] = '{}:{}'.format(host, port)
config['api_scheme'] = scheme config['api_scheme'] = scheme
config['api_key'] = api_key
config['api_prefix'] = prefix config['api_prefix'] = prefix
return config return config
@ -107,6 +115,8 @@ def update_store(store_path, store_data):
store_file = '{}/pvc-cli.json'.format(store_path) store_file = '{}/pvc-cli.json'.format(store_path)
with open(store_file, 'w') as fh: with open(store_file, 'w') as fh:
fh.write(json.dumps(store_data, sort_keys=True, indent=4)) fh.write(json.dumps(store_data, sort_keys=True, indent=4))
# Ensure file has 0600 permissions due to API key storage
os.chmod(store_file, 0o600)
home_dir = os.environ.get('HOME', None) home_dir = os.environ.get('HOME', None)
if home_dir: if home_dir:
@ -158,10 +168,14 @@ def cli_cluster():
'-s/-S', '--ssl/--no-ssl', 'ssl', is_flag=True, default=False, show_default=True, '-s/-S', '--ssl/--no-ssl', 'ssl', is_flag=True, default=False, show_default=True,
help='Whether to use SSL or not.' help='Whether to use SSL or not.'
) )
@click.option(
'-k', '--api-key', 'api_key', required=False, default=None,
help='An API key to authenticate against the cluster.'
)
@click.argument( @click.argument(
'name' 'name'
) )
def cluster_add(address, port, ssl, name): def cluster_add(address, port, ssl, name, api_key):
""" """
Add a new PVC cluster NAME, via its API connection details, to the configuration of the local CLI client. Replaces any existing cluster with this name. Add a new PVC cluster NAME, via its API connection details, to the configuration of the local CLI client. Replaces any existing cluster with this name.
""" """
@ -176,7 +190,8 @@ def cluster_add(address, port, ssl, name):
existing_config[name] = { existing_config[name] = {
'host': address, 'host': address,
'port': port, 'port': port,
'scheme': scheme 'scheme': scheme,
'api_key': api_key
} }
# Update the store # Update the store
update_store(store_path, existing_config) update_store(store_path, existing_config)
@ -218,7 +233,8 @@ def cluster_list():
name_length = 5 name_length = 5
address_length = 10 address_length = 10
port_length = 5 port_length = 5
scheme_length = 5 scheme_length = 7
api_key_length = 8
for cluster in clusters: for cluster in clusters:
cluster_details = clusters[cluster] cluster_details = clusters[cluster]
@ -226,13 +242,16 @@ def cluster_list():
# This is a reference to an API configuration; grab the details from its listen address # This is a reference to an API configuration; grab the details from its listen address
cfgfile = cluster_details.get('cfgfile') cfgfile = cluster_details.get('cfgfile')
if os.path.isfile(cfgfile): if os.path.isfile(cfgfile):
address, port, scheme = read_from_yaml(cfgfile) address, port, scheme, api_key = read_from_yaml(cfgfile)
else: else:
address, port, scheme = 'N/A', 'N/A', 'N/A' address, port, scheme, api_key = 'N/A', 'N/A', 'N/A', 'N/A'
else: else:
address = cluster_details.get('host', 'N/A') address = cluster_details.get('host', 'N/A')
port = cluster_details.get('port', 'N/A') port = cluster_details.get('port', 'N/A')
scheme = cluster_details.get('scheme', 'N/A') scheme = cluster_details.get('scheme', 'N/A')
api_key = cluster_details.get('api_key', 'N/A')
if not api_key:
api_key = 'N/A'
_name_length = len(cluster) + 1 _name_length = len(cluster) + 1
if _name_length > name_length: if _name_length > name_length:
@ -246,12 +265,15 @@ def cluster_list():
_scheme_length = len(scheme) + 1 _scheme_length = len(scheme) + 1
if _scheme_length > scheme_length: if _scheme_length > scheme_length:
scheme_length = _scheme_length scheme_length = _scheme_length
_api_key_length = len(api_key) + 1
if _api_key_length > api_key_length:
api_key_length = _api_key_length
# Display the data nicely # Display the data nicely
click.echo("Available clusters:") click.echo("Available clusters:")
click.echo() click.echo()
click.echo( click.echo(
'{bold}{name: <{name_length}} {address: <{address_length}} {port: <{port_length}} {scheme: <{scheme_length}}{end_bold}'.format( '{bold}{name: <{name_length}} {address: <{address_length}} {port: <{port_length}} {scheme: <{scheme_length}} {api_key: <{api_key_length}}{end_bold}'.format(
bold=ansiprint.bold(), bold=ansiprint.bold(),
end_bold=ansiprint.end(), end_bold=ansiprint.end(),
name="Name", name="Name",
@ -261,7 +283,9 @@ def cluster_list():
port="Port", port="Port",
port_length=port_length, port_length=port_length,
scheme="Scheme", scheme="Scheme",
scheme_length=scheme_length scheme_length=scheme_length,
api_key="API Key",
api_key_length=api_key_length
) )
) )
@ -270,18 +294,22 @@ def cluster_list():
if cluster_details.get('cfgfile', None): if cluster_details.get('cfgfile', None):
# This is a reference to an API configuration; grab the details from its listen address # This is a reference to an API configuration; grab the details from its listen address
if os.path.isfile(cfgfile): if os.path.isfile(cfgfile):
address, port, scheme = read_from_yaml(cfgfile) address, port, scheme, api_key = read_from_yaml(cfgfile)
else: else:
address = 'N/A' address = 'N/A'
port = 'N/A' port = 'N/A'
scheme = 'N/A' scheme = 'N/A'
api_key = 'N/A'
else: else:
address = cluster_details.get('host', 'N/A') address = cluster_details.get('host', 'N/A')
port = cluster_details.get('port', 'N/A') port = cluster_details.get('port', 'N/A')
scheme = cluster_details.get('scheme', 'N/A') scheme = cluster_details.get('scheme', 'N/A')
api_key = cluster_details.get('api_key', 'N/A')
if not api_key:
api_key = 'N/A'
click.echo( click.echo(
'{bold}{name: <{name_length}} {address: <{address_length}} {port: <{port_length}} {scheme: <{scheme_length}}{end_bold}'.format( '{bold}{name: <{name_length}} {address: <{address_length}} {port: <{port_length}} {scheme: <{scheme_length}} {api_key: <{api_key_length}}{end_bold}'.format(
bold='', bold='',
end_bold='', end_bold='',
name=cluster, name=cluster,
@ -291,7 +319,9 @@ def cluster_list():
port=port, port=port,
port_length=port_length, port_length=port_length,
scheme=scheme, scheme=scheme,
scheme_length=scheme_length scheme_length=scheme_length,
api_key=api_key,
api_key_length=api_key_length
) )
) )