From d7e1948d9e2a182706f10c6c8f4b93d63e1dd987 Mon Sep 17 00:00:00 2001 From: Jon Ander Novella Date: Thu, 25 Oct 2018 13:08:44 +0200 Subject: [PATCH 01/12] Added first version of cli with simple lookup --- jerakia/cli.py | 39 +++++++++++++++++++++++++++++++++++++++ setup.py | 12 ++++++++++-- 2 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 jerakia/cli.py diff --git a/jerakia/cli.py b/jerakia/cli.py new file mode 100644 index 0000000..8b94f39 --- /dev/null +++ b/jerakia/cli.py @@ -0,0 +1,39 @@ +import sys +import os +from .client import Client,ClientError +from pkg_resources import iter_entry_points +import click +from click_plugins import with_plugins + +sys.path.insert(0, os.getcwd()) + +@with_plugins(iter_entry_points('jerakia.plugins')) +@click.group() +def main(): + """jerakia is a tool to perform hierarchical data lookups.""" + +@main.command() +@click.argument('namespace') +@click.argument('key') +@click.argument('token') +@click.argument('metadata', required=False) +def lookup(namespace,key,token,metadata): + """perform a lookup using Jerakia""" + jerakiaobj = Client(token=token) + ns = [] + ret = [] + ns.append(str(namespace)) + response = jerakiaobj.lookup(key=str(key), namespace=ns, metadata_dict=metadata,content_type='json') + ret.append(response['payload']) + + if len(ret) == 1: + try: + print ("Result outputs", response['payload'].encode('ascii', 'ignore')) + except Exception as detail: + print 'The Jerakia lookup resulted in an empty response:', detail + else: + try: + [x.encode('ascii', 'ignore') for x in ret] + print ("Result outputs ", ret) + except Exception as detail: + print 'The Jerakia lookup resulted in an empty response:', detail \ No newline at end of file diff --git a/setup.py b/setup.py index 3013057..bf8236c 100644 --- a/setup.py +++ b/setup.py @@ -2,13 +2,14 @@ setup( name='python-jerakia', - version='0.5.0', + version='0.5.1', packages=find_packages(), include_package_data=True, description='Python client library for Jerakia (https://jerakia.io)', author='Jon Ander Novella', install_requires=[ 'requests>=2.0', + 'click>=6.7', 'msgpack', 'mock', 'jinja2', @@ -16,5 +17,12 @@ 'six', 'cryptography>=2.2.1', 'pyOpenSSL' - ] + ], + entry_points=''' + [console_scripts] + jerakia=jerakia.cli:main + ''', + extras_require = { + 'kcli': ["kcli"] + } ) From 61be333230d343a9c95a89560aa167aa42aaa604 Mon Sep 17 00:00:00 2001 From: Jon Ander Novella Date: Fri, 26 Oct 2018 14:11:36 +0200 Subject: [PATCH 02/12] Updates to lookup method --- jerakia/cli.py | 70 +++++++++++++++++++++++++++++++++++++++++++++----- setup.py | 2 +- 2 files changed, 64 insertions(+), 8 deletions(-) diff --git a/jerakia/cli.py b/jerakia/cli.py index 8b94f39..33bd41b 100644 --- a/jerakia/cli.py +++ b/jerakia/cli.py @@ -1,12 +1,53 @@ import sys import os +import collections +import errno +import subprocess +import six +import click +from os import walk from .client import Client,ClientError from pkg_resources import iter_entry_points -import click from click_plugins import with_plugins +from distutils import dir_util # https://github.com/PyCQA/pylint/issues/73; pylint: disable=no-name-in-module sys.path.insert(0, os.getcwd()) +class InvalidDataFormat(Exception): + """Invalid data exception""" + pass + +class InvalidInputData(Exception): + """Invalid input data exception""" + pass + +class MalformedYAML(InvalidInputData): + """Invalid YAML data exception""" + pass + +def get_format(fmt): + """Returns a data loading function""" + try: + return FORMATS[fmt]() + except ImportError: + raise InvalidDataFormat(fmt) + +def _load_yaml(): + import yaml + return yaml.load, yaml.YAMLError, MalformedYAML + +def merge_dict(a, b): + """Merge Jerakia coniguration""" + a = a.copy() + a.update(b) + return a + +FORMATS = { + 'yaml': _load_yaml, + 'yml': _load_yaml, +} + + @with_plugins(iter_entry_points('jerakia.plugins')) @click.group() def main(): @@ -15,15 +56,27 @@ def main(): @main.command() @click.argument('namespace') @click.argument('key') -@click.argument('token') -@click.argument('metadata', required=False) -def lookup(namespace,key,token,metadata): - """perform a lookup using Jerakia""" +@click.option('-T','--token') +@click.option('-P','--port') +@click.option('-t','--type') +@click.option('-H','--host') +@click.option('--protocol', default='http') +@click.option('-p','--policy') +@click.option('-m', '--metadata') +@click.option('-i', '--configfile', type=click.Path(), default='$HOME/.jerakia/jerakia.yaml') +def lookup(namespace,key,token,port,type,host,protocol,policy,metadata,configfile): + if os.path.exists(configfile): + with open(configfile, "r") as filename: + config = yaml.load(filename) + else: + config = dict() + options_config = dict(token=token,port=port,host=host,version=1,protocol=protocol) + combined_config = merge_dict(a=config,b=options_config) jerakiaobj = Client(token=token) ns = [] ret = [] ns.append(str(namespace)) - response = jerakiaobj.lookup(key=str(key), namespace=ns, metadata_dict=metadata,content_type='json') + response = jerakiaobj.lookup(key=str(key), namespace=ns, metadata_dict=metadata, content_type='json') ret.append(response['payload']) if len(ret) == 1: @@ -36,4 +89,7 @@ def lookup(namespace,key,token,metadata): [x.encode('ascii', 'ignore') for x in ret] print ("Result outputs ", ret) except Exception as detail: - print 'The Jerakia lookup resulted in an empty response:', detail \ No newline at end of file + print 'The Jerakia lookup resulted in an empty response:', detail + +if __name__ == '__main__': + greet(auto_envvar_prefix='JERAKIA') \ No newline at end of file diff --git a/setup.py b/setup.py index bf8236c..adc366a 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='python-jerakia', - version='0.5.1', + version='0.5.5', packages=find_packages(), include_package_data=True, description='Python client library for Jerakia (https://jerakia.io)', From 090d00d4bf3f90b00bd43d332a5ba696cff68233 Mon Sep 17 00:00:00 2001 From: Jon Ander Novella Date: Wed, 31 Oct 2018 16:02:35 +0100 Subject: [PATCH 03/12] =?UTF-8?q?=C3=9Cpdated=20CLI=20with=20new=20default?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jerakia/cli.py | 20 ++++++++++---------- setup.py | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/jerakia/cli.py b/jerakia/cli.py index 33bd41b..f293c6c 100644 --- a/jerakia/cli.py +++ b/jerakia/cli.py @@ -36,11 +36,11 @@ def _load_yaml(): import yaml return yaml.load, yaml.YAMLError, MalformedYAML -def merge_dict(a, b): - """Merge Jerakia coniguration""" - a = a.copy() - a.update(b) - return a +def merge_dicts(*dicts): + result = {} + for dictionary in dicts: + result.update(dictionary) + return result FORMATS = { 'yaml': _load_yaml, @@ -56,10 +56,10 @@ def main(): @main.command() @click.argument('namespace') @click.argument('key') -@click.option('-T','--token') -@click.option('-P','--port') +@click.option('-T','--token', required='true') +@click.option('-P','--port', default='9843') @click.option('-t','--type') -@click.option('-H','--host') +@click.option('-H','--host', default='localhost') @click.option('--protocol', default='http') @click.option('-p','--policy') @click.option('-m', '--metadata') @@ -71,8 +71,8 @@ def lookup(namespace,key,token,port,type,host,protocol,policy,metadata,configfil else: config = dict() options_config = dict(token=token,port=port,host=host,version=1,protocol=protocol) - combined_config = merge_dict(a=config,b=options_config) - jerakiaobj = Client(token=token) + combined_config = merge_dicts(config,options_config) + jerakiaobj = Client(**combined_config) ns = [] ret = [] ns.append(str(namespace)) diff --git a/setup.py b/setup.py index adc366a..405bc04 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='python-jerakia', - version='0.5.5', + version='0.6.0', packages=find_packages(), include_package_data=True, description='Python client library for Jerakia (https://jerakia.io)', From 765003bc0d4c39fb7195febe6c28e63f1831ab7d Mon Sep 17 00:00:00 2001 From: Jon Ander Novella Date: Wed, 31 Oct 2018 16:32:32 +0100 Subject: [PATCH 04/12] Token is now not required but CLI --- jerakia/cli.py | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/jerakia/cli.py b/jerakia/cli.py index f293c6c..2a71ad8 100644 --- a/jerakia/cli.py +++ b/jerakia/cli.py @@ -56,7 +56,7 @@ def main(): @main.command() @click.argument('namespace') @click.argument('key') -@click.option('-T','--token', required='true') +@click.option('-T','--token') @click.option('-P','--port', default='9843') @click.option('-t','--type') @click.option('-H','--host', default='localhost') @@ -72,24 +72,28 @@ def lookup(namespace,key,token,port,type,host,protocol,policy,metadata,configfil config = dict() options_config = dict(token=token,port=port,host=host,version=1,protocol=protocol) combined_config = merge_dicts(config,options_config) - jerakiaobj = Client(**combined_config) - ns = [] - ret = [] - ns.append(str(namespace)) - response = jerakiaobj.lookup(key=str(key), namespace=ns, metadata_dict=metadata, content_type='json') - ret.append(response['payload']) + if (combined_config['token'] is not None): + jerakiaobj = Client(**combined_config) + ns = [] + ret = [] + ns.append(str(namespace)) + response = jerakiaobj.lookup(key=str(key), namespace=ns, metadata_dict=metadata, content_type='json') + ret.append(response['payload']) - if len(ret) == 1: - try: - print ("Result outputs", response['payload'].encode('ascii', 'ignore')) - except Exception as detail: - print 'The Jerakia lookup resulted in an empty response:', detail + if len(ret) == 1: + try: + print ("Result outputs", response['payload'].encode('ascii', 'ignore')) + except Exception as detail: + print 'The Jerakia lookup resulted in an empty response:', detail + else: + try: + [x.encode('ascii', 'ignore') for x in ret] + print ("Result outputs ", ret) + except Exception as detail: + print 'The Jerakia lookup resulted in an empty response:', detail else: - try: - [x.encode('ascii', 'ignore') for x in ret] - print ("Result outputs ", ret) - except Exception as detail: - print 'The Jerakia lookup resulted in an empty response:', detail + print "Token was not provided. Lookup was aborted." + raise ClientError("""Token was not provided. Lookup was aborted.""") if __name__ == '__main__': greet(auto_envvar_prefix='JERAKIA') \ No newline at end of file From b9d36fb0e2db76c74434cbff931e4366b99019ce Mon Sep 17 00:00:00 2001 From: Jon Ander Novella Date: Mon, 5 Nov 2018 12:03:18 +0100 Subject: [PATCH 05/12] Minor fixes --- jerakia/cli.py | 9 ++++----- setup.py | 6 ++++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/jerakia/cli.py b/jerakia/cli.py index 2a71ad8..7b9666c 100644 --- a/jerakia/cli.py +++ b/jerakia/cli.py @@ -47,13 +47,10 @@ def merge_dicts(*dicts): 'yml': _load_yaml, } - -@with_plugins(iter_entry_points('jerakia.plugins')) @click.group() def main(): """jerakia is a tool to perform hierarchical data lookups.""" - -@main.command() +@main.command('lookup',short_help='Lookup command') @click.argument('namespace') @click.argument('key') @click.option('-T','--token') @@ -72,6 +69,8 @@ def lookup(namespace,key,token,port,type,host,protocol,policy,metadata,configfil config = dict() options_config = dict(token=token,port=port,host=host,version=1,protocol=protocol) combined_config = merge_dicts(config,options_config) + print options_config + print combined_config if (combined_config['token'] is not None): jerakiaobj = Client(**combined_config) ns = [] @@ -96,4 +95,4 @@ def lookup(namespace,key,token,port,type,host,protocol,policy,metadata,configfil raise ClientError("""Token was not provided. Lookup was aborted.""") if __name__ == '__main__': - greet(auto_envvar_prefix='JERAKIA') \ No newline at end of file + lookup(auto_envvar_prefix='JERAKIA') \ No newline at end of file diff --git a/setup.py b/setup.py index 405bc04..62fe791 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='python-jerakia', - version='0.6.0', + version='0.6.8', packages=find_packages(), include_package_data=True, description='Python client library for Jerakia (https://jerakia.io)', @@ -21,8 +21,10 @@ entry_points=''' [console_scripts] jerakia=jerakia.cli:main + [root.plugins] + plugin=jerakia.cli:main ''', extras_require = { 'kcli': ["kcli"] } -) +) \ No newline at end of file From b3ccb38d12b22b1678b5db7103cf434ee4665e15 Mon Sep 17 00:00:00 2001 From: Jon Ander Novella Date: Wed, 7 Nov 2018 11:11:30 +0100 Subject: [PATCH 06/12] cli overhaul --- jerakia/cli.py | 18 ++++++------------ setup.py | 2 +- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/jerakia/cli.py b/jerakia/cli.py index 7b9666c..4728e17 100644 --- a/jerakia/cli.py +++ b/jerakia/cli.py @@ -50,14 +50,14 @@ def merge_dicts(*dicts): @click.group() def main(): """jerakia is a tool to perform hierarchical data lookups.""" -@main.command('lookup',short_help='Lookup command') +@main.command('lookup') @click.argument('namespace') @click.argument('key') -@click.option('-T','--token') -@click.option('-P','--port', default='9843') +@click.option('-T','--token', envvar='JERAKIA_TOKEN') +@click.option('-P','--port', default='9843', envvar='JERAKIA_PORT') +@click.option('-H','--host', default='localhost', envvar='JERAKIA_HOST') +@click.option('--protocol', default='http', envvar='JERAKIA_PROTOCOL') @click.option('-t','--type') -@click.option('-H','--host', default='localhost') -@click.option('--protocol', default='http') @click.option('-p','--policy') @click.option('-m', '--metadata') @click.option('-i', '--configfile', type=click.Path(), default='$HOME/.jerakia/jerakia.yaml') @@ -69,8 +69,6 @@ def lookup(namespace,key,token,port,type,host,protocol,policy,metadata,configfil config = dict() options_config = dict(token=token,port=port,host=host,version=1,protocol=protocol) combined_config = merge_dicts(config,options_config) - print options_config - print combined_config if (combined_config['token'] is not None): jerakiaobj = Client(**combined_config) ns = [] @@ -91,8 +89,4 @@ def lookup(namespace,key,token,port,type,host,protocol,policy,metadata,configfil except Exception as detail: print 'The Jerakia lookup resulted in an empty response:', detail else: - print "Token was not provided. Lookup was aborted." - raise ClientError("""Token was not provided. Lookup was aborted.""") - -if __name__ == '__main__': - lookup(auto_envvar_prefix='JERAKIA') \ No newline at end of file + print "Token not found in env var JERAKIA_TOKEN, aborting" \ No newline at end of file diff --git a/setup.py b/setup.py index 62fe791..14b99f6 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='python-jerakia', - version='0.6.8', + version='0.8.0', packages=find_packages(), include_package_data=True, description='Python client library for Jerakia (https://jerakia.io)', From bb448dd6c99cf4a8c733297b3ede54ffe5ea19e9 Mon Sep 17 00:00:00 2001 From: Jon Ander Novella Date: Wed, 7 Nov 2018 16:44:14 +0100 Subject: [PATCH 07/12] cli now accepts multiple metadata values --- jerakia/cli.py | 12 ++++++++++-- setup.py | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/jerakia/cli.py b/jerakia/cli.py index 4728e17..521c327 100644 --- a/jerakia/cli.py +++ b/jerakia/cli.py @@ -59,22 +59,30 @@ def main(): @click.option('--protocol', default='http', envvar='JERAKIA_PROTOCOL') @click.option('-t','--type') @click.option('-p','--policy') -@click.option('-m', '--metadata') +@click.option('-m','--metadata',required=False, multiple=True) @click.option('-i', '--configfile', type=click.Path(), default='$HOME/.jerakia/jerakia.yaml') def lookup(namespace,key,token,port,type,host,protocol,policy,metadata,configfile): + # Parse metadata options + met = dict() + for item in metadata: + met.update([item.split(':')]) + # Load configfile if exists if os.path.exists(configfile): with open(configfile, "r") as filename: config = yaml.load(filename) + # Merge dicts from cli args/env vars with config file else: config = dict() options_config = dict(token=token,port=port,host=host,version=1,protocol=protocol) combined_config = merge_dicts(config,options_config) + + # Perform lookup if (combined_config['token'] is not None): jerakiaobj = Client(**combined_config) ns = [] ret = [] ns.append(str(namespace)) - response = jerakiaobj.lookup(key=str(key), namespace=ns, metadata_dict=metadata, content_type='json') + response = jerakiaobj.lookup(key=str(key), namespace=ns, metadata_dict=met, content_type='json') ret.append(response['payload']) if len(ret) == 1: diff --git a/setup.py b/setup.py index 14b99f6..18e1cbe 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='python-jerakia', - version='0.8.0', + version='0.8.1', packages=find_packages(), include_package_data=True, description='Python client library for Jerakia (https://jerakia.io)', From 35842094d7065a4c0fc91b1ef09726df90955ecd Mon Sep 17 00:00:00 2001 From: Jon Ander Novella Date: Thu, 8 Nov 2018 09:21:00 +0100 Subject: [PATCH 08/12] Updated metadata delimiter to equals sign --- jerakia/cli.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/jerakia/cli.py b/jerakia/cli.py index 521c327..30b8b64 100644 --- a/jerakia/cli.py +++ b/jerakia/cli.py @@ -65,7 +65,7 @@ def lookup(namespace,key,token,port,type,host,protocol,policy,metadata,configfil # Parse metadata options met = dict() for item in metadata: - met.update([item.split(':')]) + met.update([item.split('=')]) # Load configfile if exists if os.path.exists(configfile): with open(configfile, "r") as filename: diff --git a/setup.py b/setup.py index 18e1cbe..ebfec5f 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='python-jerakia', - version='0.8.1', + version='0.8.2', packages=find_packages(), include_package_data=True, description='Python client library for Jerakia (https://jerakia.io)', From 386ce49cdd27e246c271db8d9cd42bc26d14d8a8 Mon Sep 17 00:00:00 2001 From: Jon Ander Novella Date: Fri, 9 Nov 2018 10:53:07 +0100 Subject: [PATCH 09/12] Render method now takes metadata arg --- jerakia/render.py | 8 ++++++-- setup.py | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/jerakia/render.py b/jerakia/render.py index 2489356..8788271 100644 --- a/jerakia/render.py +++ b/jerakia/render.py @@ -9,12 +9,15 @@ from jinja2.ext import Extension jerakia = None +metadata = None -def render(template_path, jerakia_instance, data, extensions=None, strict=False): +def render(template_path, jerakia_instance, metadata_dict, data, extensions=None, strict=False): """Renders a jinja2 template using data looked up via Jerakia""" global jerakia jerakia = jerakia_instance + global metadata + metadata = metadata_dict if extensions is None: extensions = [] @@ -37,12 +40,13 @@ def retrieveJerakia(item): """Retrieves the result from the Jerakia lookup""" global jerakia + global metadata lookuppath =item.split('/') key = lookuppath.pop() namespace = lookuppath ret = [] - response = jerakia.lookup(key=key, namespace=namespace, content_type='json') + response = jerakia.lookup(key=key, namespace=namespace, metadata_dict=metadata, content_type='json') ret.append(response['payload']) if len(ret) == 1: diff --git a/setup.py b/setup.py index ebfec5f..22bbe51 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='python-jerakia', - version='0.8.2', + version='0.8.4', packages=find_packages(), include_package_data=True, description='Python client library for Jerakia (https://jerakia.io)', From 13e4089c467a82d87d85cfc05a13256772a02c1a Mon Sep 17 00:00:00 2001 From: Jon Ander Novella Date: Fri, 9 Nov 2018 11:33:44 +0100 Subject: [PATCH 10/12] Added metadata arg to mock test --- tests/test_jerakia.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_jerakia.py b/tests/test_jerakia.py index 27088be..41165be 100644 --- a/tests/test_jerakia.py +++ b/tests/test_jerakia.py @@ -123,7 +123,7 @@ def test_render_json(self,mock_lookup): fields = {'it': 'common/test'} if 'it' in fields: - test_out = render.render(template_path=config_file_path, jerakia_instance=instance, data=fields) + test_out = render.render(template_path=config_file_path, jerakia_instance=instance, metadata_dict=dict(env: 'dev'), data=fields) self.assertIsNotNone(test_out) expected_test_out = '{' + "fieldA: 'sesame'" + ', ' + "fieldB: test" + '}'+ '\n' self.assertEqual(test_out, expected_test_out) From e6d297c0f5c845bbb7f44a8396b00d979f3db666 Mon Sep 17 00:00:00 2001 From: Jon Ander Novella Date: Fri, 9 Nov 2018 11:38:13 +0100 Subject: [PATCH 11/12] Fixed syntax error --- tests/test_jerakia.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_jerakia.py b/tests/test_jerakia.py index 41165be..056d0f2 100644 --- a/tests/test_jerakia.py +++ b/tests/test_jerakia.py @@ -123,7 +123,7 @@ def test_render_json(self,mock_lookup): fields = {'it': 'common/test'} if 'it' in fields: - test_out = render.render(template_path=config_file_path, jerakia_instance=instance, metadata_dict=dict(env: 'dev'), data=fields) + test_out = render.render(template_path=config_file_path, jerakia_instance=instance, metadata_dict=dict(env='dev'), data=fields) self.assertIsNotNone(test_out) expected_test_out = '{' + "fieldA: 'sesame'" + ', ' + "fieldB: test" + '}'+ '\n' self.assertEqual(test_out, expected_test_out) From 726bc18bbab3a61e2a1fb3bb70c8f5e451913cbc Mon Sep 17 00:00:00 2001 From: Janne Johansson Date: Wed, 6 Feb 2019 12:04:25 +0100 Subject: [PATCH 12/12] Click did not pull in click-plugins, so it would fail unless I added it manually. [...] File "/Users/jj/src/git/safespring/python-jerakia/jerakia/cli.py", line 11, in from click_plugins import with_plugins ImportError: No module named click_plugins ... pip install click_plugins .. jerakia lookup --help Usage: jerakia lookup [OPTIONS] NAMESPACE KEY --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 22bbe51..bf81207 100644 --- a/setup.py +++ b/setup.py @@ -10,6 +10,7 @@ install_requires=[ 'requests>=2.0', 'click>=6.7', + 'click-plugins', 'msgpack', 'mock', 'jinja2', @@ -27,4 +28,4 @@ extras_require = { 'kcli': ["kcli"] } -) \ No newline at end of file +)