From: DW Talton Date: Thu, 12 Dec 2019 00:26:02 +0000 (-0700) Subject: Implement the Nexus 3 REST API in lftools X-Git-Tag: v0.30.0~2 X-Git-Url: https://gerrit.linuxfoundation.org/infra/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F07%2F62607%2F16;p=releng%2Flftools.git Implement the Nexus 3 REST API in lftools Issue: RELENG-308 Signed-off-by: DW Talton Change-Id: I3dc1b1b7280fe6a2d69a75e2f8c7f5a9d64c5126 --- diff --git a/.coafile b/.coafile index dea5fbc0..9412814c 100644 --- a/.coafile +++ b/.coafile @@ -34,6 +34,7 @@ bears = BanditBear, PyImportSortBear files = lftools/**.py ignore += docs/conf.py +ignore += lftools/cli/nexus3/*.py known_first_party_imports = lftools known_third_party_imports = defusedxml, diff --git a/docs/commands/index.rst b/docs/commands/index.rst index 3aea343f..c1bc7756 100644 --- a/docs/commands/index.rst +++ b/docs/commands/index.rst @@ -19,6 +19,7 @@ It supports the following commands: lfidapi license nexus + nexus3 openstack rtd schema diff --git a/docs/commands/nexus3.rst b/docs/commands/nexus3.rst new file mode 100644 index 00000000..03db2035 --- /dev/null +++ b/docs/commands/nexus3.rst @@ -0,0 +1,71 @@ +.. _nexus3: + +****** +Nexus3 +****** + +.. program-output:: lftools nexus3 --help + +.. _nexus3_commands: + +Commands +======== + +.. contents:: Nexus3 Commands + :local: + +.. _nexus3_asset: + +asset +----- + +.. program-output:: lftools nexus3 asset --help + +.. _nexus3_privileges: + +privilege +--------- + +.. program-output:: lftools nexus3 privilege --help + +.. _nexus3_repository: + +repository +---------- + +.. program-output:: lftools nexus3 repository --help + +.. _nexus3_role: + +role +---- + +.. program-output:: lftools nexus3 role --help + +.. _nexus3_script: + +script +------ + +.. program-output:: lftools nexus3 script --help + +.. _nexus3_tag: + +tag +--- + +.. program-output:: lftools nexus3 tag --help + +.. _nexus3_task: + +task +---- + +.. program-output:: lftools nexus3 task --help + +.. _nexus3_user: + +user +---- + +.. program-output:: lftools nexus3 user --help diff --git a/lftools/api/client.py b/lftools/api/client.py index f9f3f769..0e00df27 100644 --- a/lftools/api/client.py +++ b/lftools/api/client.py @@ -21,39 +21,63 @@ class RestApi(object): """Initialize the REST API class.""" self.params = params - if params['creds']: - self.creds = params['creds'] + if params["creds"]: + self.creds = params["creds"] - if 'timeout' not in self.params: + if "timeout" not in self.params: self.timeout = None - self.endpoint = self.creds['endpoint'] + self.endpoint = self.creds["endpoint"] - if self.creds['authtype'] == 'basic': - self.username = self.creds['username'] - self.password = self.creds['password'] + if self.creds["authtype"] == "basic": + self.username = self.creds["username"] + self.password = self.creds["password"] self.r = requests.Session() self.r.auth = (self.username, self.password) - self.r.headers.update({'Content-Type': 'application/json; charset=UTF-8'}) + self.r.headers.update( + {"Content-Type": "application/json; charset=UTF-8"} + ) - if self.creds['authtype'] == 'token': - self.token = self.creds['token'] + if self.creds["authtype"] == "token": + self.token = self.creds["token"] self.r = requests.Session() - self.r.headers.update({'Authorization': 'Token {}' - .format(self.token)}) - self.r.headers.update({'Content-Type': 'application/json'}) + self.r.headers.update( + {"Authorization": "Token {}".format(self.token)} + ) + self.r.headers.update({"Content-Type": "application/json"}) def _request(self, url, method, data=None, timeout=30): """Execute the request.""" - resp = self.r.request(method, self.endpoint + url, data=data, timeout=timeout) + resp = self.r.request( + method, self.endpoint + url, data=data, timeout=timeout + ) + # Some massaging to make our gerrit python code work if resp.status_code == 409: return resp + # otherwise abort on any actual HTTP errors and suppress traceback + try: + resp.raise_for_status() + except requests.exceptions.RequestException as e: + raise e + except requests.exceptions.HTTPError as e: + raise e.args + except requests.exceptions.ConnectionError as e: + raise e + except requests.exceptions.ProxyError as e: + raise e + except requests.exceptions.Timeout as e: + raise e + except requests.exceptions.URLRequired as e: + raise e + except requests.exceptions.InvalidURL as e: + raise e + if resp.text: try: - if 'application/json' in resp.headers['Content-Type']: - remove_xssi_magic = resp.text.replace(')]}\'', '') + if "application/json" in resp.headers["Content-Type"]: + remove_xssi_magic = resp.text.replace(")]}'", "") body = json.loads(remove_xssi_magic) else: body = resp.text @@ -68,20 +92,20 @@ class RestApi(object): def get(self, url, **kwargs): """HTTP GET request.""" - return self._request(url, 'GET', **kwargs) + return self._request(url, "GET", **kwargs) def patch(self, url, **kwargs): """HTTP PATCH request.""" - return self._request(url, 'PATCH', **kwargs) + return self._request(url, "PATCH", **kwargs) def post(self, url, **kwargs): """HTTP POST request.""" - return self._request(url, 'POST', **kwargs) + return self._request(url, "POST", **kwargs) def put(self, url, **kwargs): """HTTP PUT request.""" - return self._request(url, 'PUT', **kwargs) + return self._request(url, "PUT", **kwargs) def delete(self, url, **kwargs): """HTTP DELETE request.""" - return self._request(url, 'DELETE', **kwargs) + return self._request(url, "DELETE", **kwargs) diff --git a/lftools/api/endpoints/nexus.py b/lftools/api/endpoints/nexus.py new file mode 100644 index 00000000..df4d265a --- /dev/null +++ b/lftools/api/endpoints/nexus.py @@ -0,0 +1,366 @@ +# SPDX-License-Identifier: EPL-1.0 +############################################################################## +# Copyright (c) 2019 The Linux Foundation and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +############################################################################## + +"""Nexus3 REST API interface.""" +import json +import logging + +from lftools import config +import lftools.api.client as client + +log = logging.getLogger(__name__) + + +class Nexus(client.RestApi): + """API endpoint wrapper for Nexus3.""" + + def __init__(self, **params): + """Initialize the class.""" + self.params = params + self.fqdn = self.params["fqdn"] + if "creds" not in self.params: + creds = { + "authtype": "basic", + "username": config.get_setting(self.fqdn, "username"), + "password": config.get_setting(self.fqdn, "password"), + "endpoint": config.get_setting(self.fqdn, "endpoint"), + } + params["creds"] = creds + + super(Nexus, self).__init__(**params) + + def create_role(self, name, description, privileges, roles): + """Create a new role. + + :param name: the role name + :param description: the role description + :param privileges: privileges assigned to this role + :param roles: other roles attached to this role + """ + list_of_privileges = privileges.split(",") + list_of_roles = roles.split(",") + + data = { + "id": name, + "name": name, + "description": description, + "privileges": list_of_privileges, + "roles": list_of_roles, + } + + json_data = json.dumps(data, indent=4) + result = self.post("beta/security/roles", data=json_data) + + if result[0].status_code == 200: + return "Role {} created".format(name) + else: + return "Failed to create role" + + def create_script(self, name, content): + """Create a new script. + + :param name: script name + :param content: content of the script (groovy code) + """ + data = {"name": name, "content": content, "type": "groovy"} + + json_data = json.dumps(data) + result = self.post("v1/script", data=json_data) + + if result.status_code == 204: + return "Script {} successfully added.".format(name) + else: + return "Failed to create script {}".format(name) + + def create_tag(self, name, attributes): + """Create a new tag. + + :param name: the tag name + :param attributes: the tag's attributes + """ + data = { + "name": name, + } + + if attributes is not None: + data["attributes"] = attributes + + json_data = json.dumps(data) + result = self.post("v1/tags", data=json_data)[0] + + if result.status_code == 200: + return "Tag {} successfully added.".format(name) + else: + return "Failed to create tag {}".format(name) + + def delete_script(self, name): + """Delete a script from the server. + + :param name: the script name + """ + result = self.delete("v1/script/{}".format(name)) + + if result.status_code == 204: + return "Successfully deleted {}".format(name) + else: + return "Failed to delete script {}".format(name) + + def delete_tag(self, name): + """Delete a tag from the server. + + :param name: the tag's name + """ + result = self.delete("v1/tags/{}".format(name)) + + if result.status_code == 204: + return "Tag {} successfully deleted.".format(name) + else: + return "Failed to delete tag {}.".format(name) + + def list_assets(self, repository, **kwargs): + """List the assets of a given repo. + + :param repository: repo name + """ + result = self.get("v1/assets?repository={}".format(repository))[1][ + "items" + ] + if not result: + return "This repository has no assets" + else: + item_list = [] + for item in result: + item_list.append(item["path"]) + return item_list + + def list_blobstores(self, **kwargs): + """List server blobstores.""" + result = self.get("beta/blobstores")[1] + list_of_blobstores = [] + for blob in result: + list_of_blobstores.append(blob["name"]) + return list_of_blobstores + + def list_components(self, repository, **kwargs): + """List components from a repo. + + :param repository: the repo name + """ + result = self.get("v1/components?repository={}".format(repository))[1][ + "items" + ] + if not result: + return "This repository has no components" + else: + return result + + def list_privileges(self, **kwargs): + """List server-configured privileges.""" + result = self.get("beta/security/privileges")[1] + list_of_privileges = [] + for privilege in result: + list_of_privileges.append( + [ + privilege["type"], + privilege["name"], + privilege["description"], + privilege["readOnly"], + ] + ) + return list_of_privileges + + def list_repositories(self, **kwargs): + """List server repositories.""" + result = self.get("v1/repositories")[1] + list_of_repositories = [] + for repository in result: + list_of_repositories.append(repository["name"]) + return list_of_repositories + + def list_roles(self, **kwargs): + """List server roles.""" + result = self.get("beta/security/roles")[1] + list_of_roles = [] + for role in result: + list_of_roles.append([role["name"]]) + return list_of_roles + + def list_scripts(self, **kwargs): + """List server scripts.""" + result = self.get("v1/script")[1] + list_of_scripts = [] + for script in result: + list_of_scripts.append(script["name"]) + return list_of_scripts + + def show_tag(self, name): + """Get tag details. + + :param name: tag name + :return: + """ + result = self.get("v1/tags/{}".format(name))[1] + return result + + def list_tags(self): + """List all tag.""" + result = self.get("v1/tags")[1] + list_of_tags = [] + token = result["continuationToken"] + if token is not None: + while token is not None: + for tag in result["items"]: + list_of_tags.append(tag["name"]) + result = self.get( + "v1/tags?continuationToken={}".format( + result["continuationToken"] + ) + )[1] + token = result["continuationToken"] + else: + for tag in result["items"]: + list_of_tags.append(tag["name"]) + + if list_of_tags: + return list_of_tags + else: + return "There are no tags" + + def list_tasks(self, **kwargs): + """List all tasks.""" + result = self.get("v1/tasks")[1]["items"] + list_of_tasks = [] + for task in result: + list_of_tasks.append( + [ + task["name"], + task["message"], + task["currentState"], + task["lastRunResult"], + ] + ) + return list_of_tasks + + def list_user(self, username, **kwargs): + """Show user details. + + :param username: the user's username + """ + result = self.get("beta/security/users?userId={}".format(username))[1] + user_info = [] + for user in result: + user_info.append( + [ + user["userId"], + user["firstName"], + user["lastName"], + user["emailAddress"], + user["status"], + user["roles"], + ] + ) + return user_info + + def list_users(self, **kwargs): + """List all users.""" + result = self.get("beta/security/users")[1] + list_of_users = [] + for user in result: + list_of_users.append( + [ + user["userId"], + user["firstName"], + user["lastName"], + user["emailAddress"], + user["status"], + user["roles"], + ] + ) + return list_of_users + + def staging_promotion(self, destination_repo, tag): + """Promote repo assets to a new location. + + :param destination_repo: the repo to promote into + :param tag: the tag used to identify the assets + """ + data = {"tag": tag} + json_data = json.dumps(data) + result = self.post( + "v1/staging/move/{}".format(destination_repo), data=json_data + ) + return result + + def read_script(self, name): + """Get the contents of a script. + + :param name: the script name + """ + result = self.get("v1/script/{}".format(name)) + + if result[0].status_code == 200: + return result[1] + else: + return "Failed to read script {}".format(name) + + def run_script(self, name): + """Run a script on the server. + + :param name: the script name + """ + result = self.post("v1/script/{}/run".format(name)) + + if result[0].status_code == 200: + return result[1] + else: + return "Failed to execute script {}".format(name) + + def search_asset(self, query, repository, details=False): + """Search for an asset. + + :param query: querystring to use, eg myjar-1 to find myjar-1.2.3.jar + :param repository: the repo to search in + :param details: returns a fully-detailed json dump + """ + data = { + "q": query, + "repository": repository, + } + json_data = json.dumps(data) + result = self.get( + "v1/search/assets?q={}&repository={}".format(query, repository), + data=json_data, + )[1]["items"] + list_of_assets = [] + + if details: + return json.dumps(result, indent=4) + + for item in result: + list_of_assets.append(item["path"]) + + return list_of_assets + + def update_script(self, name, content): + """Update an existing script on the server. + + :param name: script name + :param content: new content for the script (groovy code) + """ + data = {"name": name, "content": content, "type": "groovy"} + + json_data = json.dumps(data) + + result = self.put("v1/script/{}".format(name), data=json_data) + + if result.status_code == 204: + return "Successfully updated {}".format(name) + else: + return "Failed to update script {}".format(name) diff --git a/lftools/cli/__init__.py b/lftools/cli/__init__.py index 534d229d..87370a95 100644 --- a/lftools/cli/__init__.py +++ b/lftools/cli/__init__.py @@ -28,6 +28,7 @@ from lftools.cli.infofile import infofile from lftools.cli.jenkins import jenkins_cli from lftools.cli.lfidapi import lfidapi from lftools.cli.license import license +from lftools.cli.nexus3 import nexus3 from lftools.cli.nexus import nexus from lftools.cli.rtd import rtd from lftools.cli.schema import schema @@ -87,6 +88,7 @@ cli.add_command(infofile) cli.add_command(jenkins_cli, name='jenkins') cli.add_command(license) cli.add_command(nexus) +cli.add_command(nexus3) cli.add_command(rtd) cli.add_command(schema) cli.add_command(lfidapi) diff --git a/lftools/cli/nexus3/__init__.py b/lftools/cli/nexus3/__init__.py new file mode 100644 index 00000000..d4085207 --- /dev/null +++ b/lftools/cli/nexus3/__init__.py @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: EPL-1.0 +############################################################################## +# Copyright (c) 2019 The Linux Foundation and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +############################################################################## + +"""Nexus3 REST API sub-interfaces.""" + +from .asset import * +from .privilege import * +from .repository import * +from .role import * +from .script import * +from .tag import * +from .task import * +from .user import * + + +@click.group() +@click.argument("fqdn") +@click.pass_context +def nexus3(ctx, fqdn): + """Provide an interface to Nexus3.""" + nexus_obj = nexus.Nexus(fqdn=fqdn) + ctx.obj = {"nexus": nexus_obj} + pass + + +nexus3.add_command(asset) +nexus3.add_command(privilege) +nexus3.add_command(repository) +nexus3.add_command(role) +nexus3.add_command(script) +nexus3.add_command(tag) +nexus3.add_command(task) +nexus3.add_command(user) diff --git a/lftools/cli/nexus3/asset.py b/lftools/cli/nexus3/asset.py new file mode 100644 index 00000000..1aac887b --- /dev/null +++ b/lftools/cli/nexus3/asset.py @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: EPL-1.0 +############################################################################## +# Copyright (c) 2019 The Linux Foundation and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +############################################################################## + +"""Nexus3 REST API asset interface.""" + +import logging +from pprint import pformat + +import click + +from lftools.api.endpoints import nexus + +log = logging.getLogger(__name__) + + +@click.group() +@click.pass_context +def asset(ctx): + """Asset primary interface.""" + pass + + +@asset.command(name="list") +@click.argument("repository") +@click.pass_context +def asset_list(ctx, repository): + """List assets.""" + r = ctx.obj["nexus"] + data = r.list_assets(repository) + for item in data: + log.info(pformat(item)) + + +@asset.command(name="search") +@click.argument("query-string") +@click.argument("repository") +@click.option("--details", is_flag=True) +@click.pass_context +def asset_search(ctx, query_string, repository, details): + """Search assets.""" + r = ctx.obj["nexus"] + data = r.search_asset(query_string, repository, details) + + if details: + log.info(data) + else: + for item in data: + log.info(item) diff --git a/lftools/cli/nexus3/privilege.py b/lftools/cli/nexus3/privilege.py new file mode 100644 index 00000000..32841daf --- /dev/null +++ b/lftools/cli/nexus3/privilege.py @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: EPL-1.0 +############################################################################## +# Copyright (c) 2019 The Linux Foundation and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +############################################################################## + +"""Nexus3 REST API privileges interface.""" + +import logging + +import click +from tabulate import tabulate + +log = logging.getLogger(__name__) + + +@click.group() +@click.pass_context +def privilege(ctx): + """Privilege primary interface.""" + pass + + +@privilege.command(name="list") +@click.pass_context +def list_privileges(ctx): + """List privileges.""" + r = ctx.obj["nexus"] + data = r.list_privileges() + log.info( + tabulate(data, headers=["Type", "Name", "Description", "Read Only"]) + ) diff --git a/lftools/cli/nexus3/repository.py b/lftools/cli/nexus3/repository.py new file mode 100644 index 00000000..981fe13c --- /dev/null +++ b/lftools/cli/nexus3/repository.py @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: EPL-1.0 +############################################################################## +# Copyright (c) 2019 The Linux Foundation and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +############################################################################## + +"""Nexus3 REST API repository interface.""" + +import logging +from pprint import pformat + +import click + +from lftools.api.endpoints import nexus # noqa: F401 + +log = logging.getLogger(__name__) + + +@click.group() +@click.pass_context +def repository(ctx): + """Repository primary interface.""" + pass + + +@repository.command(name="list") +@click.pass_context +def list_repositories(ctx): + """List repositories.""" + r = ctx.obj["nexus"] + data = r.list_repositories() + log.info(pformat(data)) diff --git a/lftools/cli/nexus3/role.py b/lftools/cli/nexus3/role.py new file mode 100644 index 00000000..6c25e1c7 --- /dev/null +++ b/lftools/cli/nexus3/role.py @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: EPL-1.0 +############################################################################## +# Copyright (c) 2019 The Linux Foundation and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +############################################################################## + +"""Nexus3 REST API role interface.""" + +import logging +from pprint import pformat + +import click +from tabulate import tabulate + +from lftools.api.endpoints import nexus # noqa: F401 + +log = logging.getLogger(__name__) + + +@click.group() +@click.pass_context +def role(ctx): + """Role primary interface.""" + pass + + +@role.command(name="list") +@click.pass_context +def list_roles(ctx): + """List roles.""" + r = ctx.obj["nexus"] + data = r.list_roles() + log.info(tabulate(data, headers=["Roles"])) + + +@role.command(name="create") +@click.argument("name") +@click.argument("description") +@click.argument("privileges") +@click.argument("roles") +@click.pass_context +def create_role(ctx, name, description, privileges, roles): + """Create roles.""" + r = ctx.obj["nexus"] + data = r.create_role(name, description, privileges, roles) + log.info(pformat(data)) diff --git a/lftools/cli/nexus3/script.py b/lftools/cli/nexus3/script.py new file mode 100644 index 00000000..b02dc599 --- /dev/null +++ b/lftools/cli/nexus3/script.py @@ -0,0 +1,87 @@ +# SPDX-License-Identifier: EPL-1.0 +############################################################################## +# Copyright (c) 2019 The Linux Foundation and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +############################################################################## + +"""Nexus3 REST API script interface.""" + +import logging + +import click + +from lftools.api.endpoints import nexus # noqa: F401 + +log = logging.getLogger(__name__) + + +@click.group() +@click.pass_context +def script(ctx): + """Script primary interface.""" + pass + + +@script.command(name="create") +@click.argument("name") +@click.argument("filename") +@click.pass_context +def create_script(ctx, name, filename): + """Create a new script.""" + r = ctx.obj["nexus"] + data = r.create_script(name, filename) + log.info(data) + + +@script.command(name="delete") +@click.argument("name") +@click.pass_context +def delete_script(ctx, name): + """Delete a script.""" + r = ctx.obj["nexus"] + data = r.delete_script(name) + log.info(data) + + +@script.command(name="list") +@click.pass_context +def list_scripts(ctx): + """List all scripts.""" + r = ctx.obj["nexus"] + data = r.list_scripts() + log.info(data) + + +@script.command(name="read") +@click.argument("name") +@click.pass_context +def read_script(ctx, name): + """Get script contents.""" + r = ctx.obj["nexus"] + data = r.read_script(name) + log.info(data) + + +@script.command(name="run") +@click.argument("name") +@click.pass_context +def run_script(ctx, name): + """Run a script.""" + r = ctx.obj["nexus"] + data = r.run_script(name) + log.info(data) + + +@script.command(name="update") +@click.argument("name") +@click.argument("content") +@click.pass_context +def update_script(ctx, name, content): + """Update script contents.""" + r = ctx.obj["nexus"] + data = r.update_script(name, content) + log.info(data) diff --git a/lftools/cli/nexus3/tag.py b/lftools/cli/nexus3/tag.py new file mode 100644 index 00000000..c98606d8 --- /dev/null +++ b/lftools/cli/nexus3/tag.py @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: EPL-1.0 +############################################################################## +# Copyright (c) 2019 The Linux Foundation and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +############################################################################## + +"""Nexus3 REST API tag interface.""" + +import logging +from pprint import pformat + +import click + +log = logging.getLogger(__name__) + + +@click.group() +@click.pass_context +def tag(ctx): + """Tag primary interface.""" + pass + + +@tag.command(name="add") +@click.argument("name") +@click.argument("attributes", required=False) +@click.pass_context +def add_tag(ctx, name, attributes): + """Add a tag.""" + r = ctx.obj["nexus"] + data = r.create_tag(name, attributes) + log.info(pformat(data)) + + +@tag.command(name="delete") +@click.argument("name") +@click.pass_context +def delete_tag(ctx, name): + """Delete a tag.""" + r = ctx.obj["nexus"] + data = r.delete_tag(name) + log.info(pformat(data)) + + +@tag.command(name="list") +@click.pass_context +def list_tags(ctx): + """List tags.""" + r = ctx.obj["nexus"] + data = r.list_tags() + log.info(pformat(data)) + + +@tag.command(name="show") +@click.argument("name") +@click.pass_context +def show_tag(ctx, name): + """Show tags.""" + r = ctx.obj["nexus"] + data = r.show_tag(name) + log.info(pformat(data)) diff --git a/lftools/cli/nexus3/task.py b/lftools/cli/nexus3/task.py new file mode 100644 index 00000000..5d30e253 --- /dev/null +++ b/lftools/cli/nexus3/task.py @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: EPL-1.0 +############################################################################## +# Copyright (c) 2019 The Linux Foundation and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +############################################################################## + +"""Nexus3 REST API task interface.""" +import logging + +import click +from tabulate import tabulate + +from lftools.api.endpoints import nexus # noqa: F401 + +log = logging.getLogger(__name__) + + +@click.group() +@click.pass_context +def task(ctx): + """Task primary interface.""" + pass + + +@task.command(name="list") +@click.pass_context +def list_tasks(ctx): + """List tasks.""" + r = ctx.obj["nexus"] + data = r.list_tasks() + log.info( + tabulate( + data, + headers=["Name", "Message", "Current State", "Last Run Result"], + ) + ) diff --git a/lftools/cli/nexus3/user.py b/lftools/cli/nexus3/user.py new file mode 100644 index 00000000..43821a74 --- /dev/null +++ b/lftools/cli/nexus3/user.py @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: EPL-1.0 +############################################################################## +# Copyright (c) 2019 The Linux Foundation and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +############################################################################## + +"""Nexus3 REST API user interface.""" + +import logging + +import click +from tabulate import tabulate + +from lftools.api.endpoints import nexus # noqa: F401 + +log = logging.getLogger(__name__) + + +@click.group() +@click.pass_context +def user(ctx): + """User primary interface.""" + pass + + +@user.command(name="search") +@click.argument("username") +@click.pass_context +def search_user(ctx, username): + """Search users.""" + r = ctx.obj["nexus"] + data = r.list_user(username) + log.info( + tabulate( + data, + headers=[ + "User ID", + "First Name", + "Last Name", + "Email Address", + "Status", + "Roles", + ], + ) + ) diff --git a/lftools/config.py b/lftools/config.py index ff39e97e..27b1abd4 100644 --- a/lftools/config.py +++ b/lftools/config.py @@ -10,11 +10,11 @@ ############################################################################## """Configuration subsystem for lftools.""" -__author__ = 'Thanh Ha' import configparser import logging import os.path +import sys from xdg import XDG_CONFIG_HOME @@ -25,7 +25,6 @@ LFTOOLS_CONFIG_FILE = os.path.join(XDG_CONFIG_HOME, 'lftools', 'lftools.ini') def get_config(): """Get the config object.""" - #config = configparser.ConfigParser(interpolation=configparser.ExtendedInterpolation()) # noqa config = configparser.ConfigParser() # noqa config.read(LFTOOLS_CONFIG_FILE) return config @@ -39,6 +38,7 @@ def has_section(section): def get_setting(section, option=None): """Get a configuration from a section.""" + sys.tracebacklimit = 0 config = get_config() if option: diff --git a/releasenotes/notes/nexus3-6a988f31e4876fd8.yaml b/releasenotes/notes/nexus3-6a988f31e4876fd8.yaml new file mode 100644 index 00000000..167f3907 --- /dev/null +++ b/releasenotes/notes/nexus3-6a988f31e4876fd8.yaml @@ -0,0 +1,23 @@ +--- +features: + - | + Nexus3 API operations. + + Usage: lftools nexus3 [OPTIONS] FQDN COMMAND [ARGS]... + + .. code-block:: none + + Commands: + asset Asset primary interface. + privilege Privilege primary interface. + repository Repository primary interface. + role Role primary interface. + script Script primary interface. + tag Tag primary interface. + task Task primary interface. + user User primary interface. + + .. code-block:: none + + Options: + --help Show this message and exit. diff --git a/requirements.txt b/requirements.txt index c3e0295d..757d7835 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,19 +1,20 @@ +bs4 click -docker defusedxml # Needed due to tox complains on parseString not safe +docker +email_validator +httplib2 jsonschema +lxml +oauth2client +pygerrit2 +pygithub +python-jenkins +pyyaml requests ruamel.yaml setuptools>=36.5.0 six -python-jenkins +tabulate tqdm xdg==3.0.2 -pygithub -httplib2 -email_validator -oauth2client -pyyaml -pygerrit2 -bs4 -lxml