diff --git a/drydock_provisioner/cli/commands.py b/drydock_provisioner/cli/commands.py index 7448436b..75e4c625 100644 --- a/drydock_provisioner/cli/commands.py +++ b/drydock_provisioner/cli/commands.py @@ -11,15 +11,17 @@ # 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. -""" The entrypoint for the cli commands +""" The entry point for the cli commands """ import os import logging -import click +from urllib.parse import urlparse +import click from drydock_provisioner.drydock_client.session import DrydockSession from drydock_provisioner.drydock_client.client import DrydockClient from .design import commands as design +from .part import commands as part @click.group() @click.option('--debug/--no-debug', @@ -43,12 +45,12 @@ def drydock(ctx, debug, token, url): ctx.obj['DEBUG'] = debug if not token: - ctx.fail("Error: Token must be specified either by " - "--token or DD_TOKEN from the environment") + ctx.fail('Error: Token must be specified either by ' + '--token or DD_TOKEN from the environment') if not url: - ctx.fail("Error: URL must be specified either by " - "--url or DD_URL from the environment") + ctx.fail('Error: URL must be specified either by ' + '--url or DD_URL from the environment') # setup logging for the CLI # Setup root logger @@ -63,7 +65,13 @@ def drydock(ctx, debug, token, url): logger.debug('logging for cli initialized') # setup the drydock client using the passed parameters. - ctx.obj['CLIENT'] = DrydockClient(DrydockSession(host=url, + url_parse_result = urlparse(url) + logger.debug(url_parse_result) + if not url_parse_result.scheme: + ctx.fail('URL must specify a scheme and hostname, optionally a port') + ctx.obj['CLIENT'] = DrydockClient(DrydockSession(scheme=url_parse_result.scheme, + host=url_parse_result.netloc, token=token)) drydock.add_command(design.design) +drydock.add_command(part.part) diff --git a/drydock_provisioner/cli/part/actions.py b/drydock_provisioner/cli/part/actions.py new file mode 100644 index 00000000..1a189e19 --- /dev/null +++ b/drydock_provisioner/cli/part/actions.py @@ -0,0 +1,87 @@ +# Copyright 2017 AT&T Intellectual Property. All other rights reserved. +# +# 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 a 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. +""" Actions related to part command +""" + + +from drydock_provisioner.cli.action import CliAction + +class PartBase(CliAction): # pylint: disable=too-few-public-methods + """ base class to set up part actions requiring a design_id + """ + def __init__(self, api_client, design_id): + super().__init__(api_client) + self.design_id = design_id + self.logger.debug('Initializing a Part action with design_id=%s', design_id) + +class PartList(PartBase): # pylint: disable=too-few-public-methods + """ Action to list parts of a design + """ + def __init__(self, api_client, design_id): + """ + :param DrydockClient api_client: The api client used for invocation. + :param string design_id: The UUID of the design for which to list parts + """ + super().__init__(api_client, design_id) + self.logger.debug('PartList action initialized') + + def invoke(self): + #TODO: change the api call + #return self.api_client.get_design_ids() + pass + +class PartCreate(PartBase): # pylint: disable=too-few-public-methods + """ Action to create parts of a design + """ + def __init__(self, api_client, design_id, yaml): + """ + :param DrydockClient api_client: The api client used for invocation. + :param string design_id: The UUID of the design for which to create a part + :param yaml: The file containing the specification of the part + """ + super().__init__(api_client, design_id) + self.yaml = yaml + self.logger.debug('PartCreate action initialized with yaml=%s', yaml[:100]) + + def invoke(self): + return self.api_client.load_parts(self.design_id, self.yaml) + +class PartShow(PartBase): # pylint: disable=too-few-public-methods + """ Action to show a part of a design. + """ + def __init__(self, api_client, design_id, kind, key, source='designed'): + """ + :param DrydockClient api_client: The api client used for invocation. + :param string design_id: the UUID of the design containing this part + :param string kind: the string represesnting the 'kind' of the document to return + :param string key: the string representing the key of the document to return. + :param string source: 'designed' (default) if this is the designed version, + 'compiled' if the compiled version (after merging) + """ + super().__init__(api_client, design_id) + self.kind = kind + self.key = key + self.source = source + self.logger.debug('DesignShow action initialized for design_id=%s,' + ' kind=%s, key=%s, source=%s', + design_id, + kind, + key, + source) + + def invoke(self): + return self.api_client.get_part(design_id=self.design_id, + kind=self.kind, + key=self.key, + source=self.source) diff --git a/drydock_provisioner/cli/part/commands.py b/drydock_provisioner/cli/part/commands.py new file mode 100644 index 00000000..86d3251b --- /dev/null +++ b/drydock_provisioner/cli/part/commands.py @@ -0,0 +1,81 @@ +# Copyright 2017 AT&T Intellectual Property. All other rights reserved. +# +# 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 a 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. +""" cli.part.commands + Contains commands related to parts of designs +""" +import click + +from drydock_provisioner.cli.part.actions import PartList +from drydock_provisioner.cli.part.actions import PartShow +from drydock_provisioner.cli.part.actions import PartCreate + +@click.group() +@click.option('--design-id', + '-d', + help='The id of the design containing the target parts') +@click.pass_context +def part(ctx, design_id=None): + """ Drydock part commands + """ + if not design_id: + ctx.fail('Error: Design id must be specified using --design-id') + + ctx.obj['DESIGN_ID'] = design_id + +@part.command(name='create') +@click.option('--file', + '-f', + help='The file name containing the part to create') +@click.pass_context +def part_create(ctx, file=None): + """ Create a part + """ + if not file: + ctx.fail('A file to create a part is required using --file') + + with open(file, 'r') as file_input: + file_contents = file_input.read() + # here is where some yaml validation could be done + click.echo(PartCreate(ctx.obj['CLIENT'], + design_id=ctx.obj['DESIGN_ID'], + yaml=file_contents).invoke()) + +@part.command(name='list') +@click.pass_context +def part_list(ctx): + """ List parts of a design + """ + click.echo(PartList(ctx.obj['CLIENT'], design_id=ctx.obj['DESIGN_ID']).invoke()) + +@part.command(name='show') +@click.option('--source', + '-s', + help='designed | compiled') +@click.option('--kind', + '-k', + help='The kind value of the document to show') +@click.option('--key', + '-i', + help='The key value of the document to show') +@click.pass_context +def part_show(ctx, source, kind, key): + """ show a part of a design + """ + if not kind: + ctx.fail('The kind must be specified by --kind') + + if not key: + ctx.fail('The key must be specified by --key') + + click.echo(PartShow(ctx.obj['CLIENT'], design_id=ctx.obj['DESIGN_ID'], kind=kind, key=key, source=source).invoke()) diff --git a/drydock_provisioner/drydock_client/session.py b/drydock_provisioner/drydock_client/session.py index 174a6670..28c3fe37 100644 --- a/drydock_provisioner/drydock_client/session.py +++ b/drydock_provisioner/drydock_client/session.py @@ -23,15 +23,19 @@ class DrydockSession(object): :param string marker: (optional) external context marker """ - def __init__(self, host, *, port=None, token=None, marker=None): + def __init__(self, host, *, port=None, scheme='http', token=None, marker=None): self.__session = requests.Session() self.__session.headers.update({'X-Auth-Token': token, 'X-Context-Marker': marker}) self.host = host - self.port = port + self.scheme = scheme + if port: - self.base_url = "http://%s:%d/api/" % (host, port) + self.port = port + self.base_url = "%s://%s:%s/api/" % (self.scheme, self.host, self.port) else: - self.base_url = "http://%s/api/" % (host) + #assume default port for scheme + self.base_url = "%s://%s/api/" % (self.scheme, self.host) + self.token = token self.marker = marker diff --git a/setup.py b/setup.py index 9b49a6a3..227af94e 100644 --- a/setup.py +++ b/setup.py @@ -43,6 +43,7 @@ setup(name='drydock_provisioner', 'drydock_provisioner.control', 'drydock_provisioner.cli', 'drydock_provisioner.cli.design', + 'drydock_provisioner.cli.part', 'drydock_provisioner.drydock_client'], install_requires=[ 'PyYAML',