259 lines
10 KiB
Python
259 lines
10 KiB
Python
import pkg_resources
|
|
import yaml
|
|
import click
|
|
import six
|
|
from gluon.common import exception as exc
|
|
from requests import get, put, post, delete
|
|
import json
|
|
|
|
|
|
def load_model(package_name, model_dir):
|
|
model = {}
|
|
for f in pkg_resources.resource_listdir(package_name, model_dir):
|
|
f = model_dir + '/' + f
|
|
with pkg_resources.resource_stream(package_name, f) as fd:
|
|
model.update(yaml.safe_load(fd))
|
|
return model
|
|
|
|
|
|
def json_get(url):
|
|
resp = get(url)
|
|
if resp.status_code != 200:
|
|
raise exc.GluonClientException('Bad return status %d'
|
|
% resp.status_code,
|
|
status_code=resp.status_code)
|
|
try:
|
|
rv = json.loads(resp.content)
|
|
except Exception as e:
|
|
raise exc.MalformedResponseBody(reason="JSON unreadable: %s on %s"
|
|
% (e.message, resp.content))
|
|
return rv
|
|
|
|
|
|
def do_delete(url):
|
|
resp = delete(url)
|
|
if resp.status_code != 200 and resp.status_code != 204:
|
|
raise exc.GluonClientException('Bad return status %d'
|
|
% resp.status_code,
|
|
status_code=resp.status_code)
|
|
|
|
|
|
def do_post(url, values):
|
|
resp = post(url, json=values)
|
|
if resp.status_code != 200 and resp.status_code != 201:
|
|
raise exc.GluonClientException('Bad return status %d'
|
|
% resp.status_code,
|
|
status_code=resp.status_code)
|
|
try:
|
|
rv = json.loads(resp.content)
|
|
except Exception as e:
|
|
raise exc.MalformedResponseBody(reason="JSON unreadable: %s on %s"
|
|
% (e.message, resp.content))
|
|
return rv
|
|
|
|
|
|
def do_put(url, values):
|
|
resp = put(url, json=values)
|
|
if resp.status_code != 200:
|
|
raise exc.GluonClientException('Bad return status %d'
|
|
% resp.status_code,
|
|
status_code=resp.status_code)
|
|
try:
|
|
rv = json.loads(resp.content)
|
|
except Exception as e:
|
|
raise exc.MalformedResponseBody(reason="JSON unreadable: %s on %s"
|
|
% (e.message, resp.content))
|
|
return rv
|
|
|
|
|
|
def make_url(host, port, *args):
|
|
url = "http://%s:%d/v1" % (host, port)
|
|
for arg in args:
|
|
url = "%s/%s" % (url, arg)
|
|
return url
|
|
|
|
|
|
def make_list_func(tablename):
|
|
def list_func(**kwargs):
|
|
url = make_url(kwargs["host"], kwargs["port"], tablename)
|
|
result = json_get(url)
|
|
print(json.dumps(result, indent=4))
|
|
|
|
return list_func
|
|
|
|
|
|
def make_show_func(tablename, primary_key):
|
|
def show_func(**kwargs):
|
|
url = make_url(kwargs["host"], kwargs["port"], tablename, kwargs[primary_key])
|
|
result = json_get(url)
|
|
print(json.dumps(result, indent=4))
|
|
|
|
return show_func
|
|
|
|
|
|
def make_create_func(tablename):
|
|
def create_func(**kwargs):
|
|
url = make_url(kwargs["host"], kwargs["port"], tablename)
|
|
del kwargs["host"]
|
|
del kwargs["port"]
|
|
data = {}
|
|
for key, val in six.iteritems(kwargs):
|
|
if val is not None:
|
|
data[key] = val
|
|
result = do_post(url, data)
|
|
print(json.dumps(result, indent=4))
|
|
|
|
return create_func
|
|
|
|
|
|
def make_update_func(tablename, primary_key):
|
|
def update_func(**kwargs):
|
|
url = make_url(kwargs["host"], kwargs["port"], tablename, kwargs[primary_key], "update")
|
|
del kwargs["host"]
|
|
del kwargs["port"]
|
|
del kwargs[primary_key]
|
|
data = {}
|
|
for key, val in six.iteritems(kwargs):
|
|
if val is not None:
|
|
data[key] = val
|
|
result = do_put(url, data)
|
|
print(json.dumps(result, indent=4))
|
|
|
|
return update_func
|
|
|
|
|
|
def make_delete_func(tablename, primary_key):
|
|
def delete_func(**kwargs):
|
|
url = make_url(kwargs["host"], kwargs["port"], tablename, kwargs[primary_key])
|
|
do_delete(url)
|
|
|
|
return delete_func
|
|
|
|
|
|
def get_primary_key(table_data):
|
|
primary = []
|
|
for k, v in six.iteritems(table_data['attributes']):
|
|
if 'primary' in v:
|
|
primary = k
|
|
break
|
|
# If not specified, a UUID is used as the PK
|
|
if not primary:
|
|
table_data['attributes']['uuid'] = \
|
|
dict(type='string', length=36, primary=True, required=True)
|
|
primary = 'uuid'
|
|
table_data['primary'] = primary
|
|
return primary
|
|
|
|
|
|
def set_type(kwargs, col_desc):
|
|
if col_desc['type'] == 'string':
|
|
pass
|
|
elif col_desc['type'] == 'integer':
|
|
kwargs["type"] = int
|
|
elif col_desc['type'] == 'boolean':
|
|
kwargs["type"] = bool
|
|
elif col_desc['type'] == 'enum':
|
|
kwargs["type"] = click.Choice(col_desc['values'])
|
|
else:
|
|
raise Exception('Unknown column type %s' % col_desc['type'])
|
|
|
|
|
|
def proc_model(cli, package_name="unknown",
|
|
model_dir="unknown",
|
|
hostenv="unknown",
|
|
portenv="unknown",
|
|
hostdefault="unknown",
|
|
portdefault=0):
|
|
# print("loading model")
|
|
model = load_model(package_name, model_dir)
|
|
for table_name, table_data in six.iteritems(model):
|
|
get_primary_key(table_data)
|
|
for table_name, table_data in six.iteritems(model):
|
|
try:
|
|
attrs = {}
|
|
for col_name, col_desc in six.iteritems(table_data['attributes']):
|
|
try:
|
|
# Step 1: deal with object xrefs
|
|
if col_desc['type'] in model:
|
|
# If referencing another object, get the type of its primary key
|
|
tgt_name = col_desc['type']
|
|
tgt_data = model[tgt_name]
|
|
primary_col = tgt_data['primary']
|
|
table_data["attributes"][col_name]['type'] = tgt_data["attributes"][primary_col]["type"]
|
|
# Step 2: convert our special types to ones a CLI likes
|
|
if col_desc['type'] == 'uuid':
|
|
# UUIDs, from a CLI perspective, are a form of
|
|
# string
|
|
table_data["attributes"][col_name]['type'] = 'string'
|
|
table_data["attributes"][col_name]['length'] = 64
|
|
if col_desc.get('primary', False):
|
|
attrs['_primary_key'] = col_name
|
|
except:
|
|
print('During processing of attribute ', col_name)
|
|
raise
|
|
if not '_primary_key' in attrs:
|
|
raise Exception("One and only one primary key has to "
|
|
"be given to each column")
|
|
attrs['__tablename__'] = table_data['api']['name']
|
|
attrs['__objname__'] = table_data['api']['name'][:-1] # chop off training 's'
|
|
#
|
|
# Create CDUD commands for the table
|
|
#
|
|
hosthelp = "Host of endpoint (%s) " % hostenv
|
|
porthelp = "Port of endpoint (%s) " % portenv
|
|
list = make_list_func(attrs['__tablename__'])
|
|
list.func_name = "%s-list" % (attrs['__objname__'])
|
|
list = click.option("--host", envvar=hostenv, default=hostdefault, help=hosthelp)(list)
|
|
list = click.option("--port", envvar=portenv, default=portdefault, help=porthelp)(list)
|
|
cli.command()(list)
|
|
|
|
show = make_show_func(attrs['__tablename__'], attrs['_primary_key'])
|
|
show.func_name = "%s-show" % (attrs['__objname__'])
|
|
show = click.option("--host", envvar=hostenv, default=hostdefault, help=hosthelp)(show)
|
|
show = click.option("--port", envvar=portenv, default=portdefault, help=porthelp)(show)
|
|
show = click.argument(attrs['_primary_key'])(show)
|
|
cli.command()(show)
|
|
|
|
create = make_create_func(attrs['__tablename__'])
|
|
create.func_name = "%s-create" % (attrs['__objname__'])
|
|
create = click.option("--host", envvar=hostenv, default=hostdefault, help=hosthelp)(create)
|
|
create = click.option("--port", envvar=portenv, default=portdefault, help=porthelp)(create)
|
|
for col_name, col_desc in six.iteritems(table_data['attributes']):
|
|
kwargs = {}
|
|
option_name = "--" + col_name
|
|
kwargs["default"] = None
|
|
required = col_desc.get('required', False)
|
|
kwargs["help"] = col_desc.get('description', "no description")
|
|
if required:
|
|
kwargs["required"] = True
|
|
set_type(kwargs, col_desc)
|
|
create = click.option(option_name, **kwargs)(create)
|
|
cli.command()(create)
|
|
|
|
update = make_update_func(attrs['__tablename__'], attrs['_primary_key'])
|
|
update.func_name = "%s-update" % (attrs['__objname__'])
|
|
update = click.option("--host", envvar=hostenv, default=hostdefault, help=hosthelp)(update)
|
|
update = click.option("--port", envvar=portenv, default=portdefault, help=porthelp)(update)
|
|
for col_name, col_desc in six.iteritems(table_data['attributes']):
|
|
if col_name == attrs['_primary_key']:
|
|
continue
|
|
kwargs = {}
|
|
option_name = "--" + col_name
|
|
kwargs["default"] = None
|
|
kwargs["help"] = col_desc.get('description', "no description")
|
|
set_type(kwargs, col_desc)
|
|
update = click.option(option_name, **kwargs)(update)
|
|
update = click.argument(attrs['_primary_key'])(update)
|
|
cli.command()(update)
|
|
|
|
del_func = make_delete_func(attrs['__tablename__'], attrs['_primary_key'])
|
|
del_func.func_name = "%s-delete" % (attrs['__objname__'])
|
|
del_func = click.option("--host", envvar=hostenv, default=hostdefault, help=hosthelp)(del_func)
|
|
del_func = click.option("--port", envvar=portenv, default=portdefault, help=porthelp)(del_func)
|
|
del_func = click.argument(attrs['_primary_key'])(del_func)
|
|
cli.command()(del_func)
|
|
|
|
except:
|
|
print('During processing of table ', table_name)
|
|
raise
|