This enables users to create Nexus roles outside of project creation.
Add docs/commands/nexus.rst to WriteGoodLintBear ignore list, due to
issues with it failing the check based on example yaml code.
Issue: RELENG-290
Change-Id: Ie51e2bcd4d03221661b3cec79f8f62ea6d3e8c39
Signed-off-by: Eric Ball <eball@linuxfoundation.org>
[all.Documentation]
bears = WriteGoodLintBear
files = docs/**/*.rst
+ignore += docs/commands/nexus.rst
[all.MarkDown]
bears = MarkdownBear,SpaceConsistencyBear,WriteGoodLintBear
For details and examples, please see
:ref:`Create Nexus2 repos with lftools <create-repos-lftools>`
+.. _nexus-role:
+
+role
+^^^^
+
+.. program-output:: lftools nexus create role --help
+
+.. code-block:: yaml
+
+ # Example role-config.yaml. The top-level keys will be the role's id.
+ ---
+ # Minimal config
+ lf-deployment:
+ name: LF Deployment Role
+ roles: # Roles can be defined by ID or by Name
+ - nx-deployment
+ - analytics
+ # Full config with privileges (by name only) and description defined.
+ LF Deployment By Name:
+ name: LF Dep Role
+ privileges:
+ - Status - (read)
+ - Login to UI
+ roles:
+ - Nexus Deployment Role
+ - Analytics
+ description: "A role where I defined its contained roles by name"
+
+
.. _nexus-reorder-staged-repos:
reorder-staged-repos
nexuscmd.create_repos(config, settings)
+@create.command()
+@click.option(
+ '-c', '--config', type=str, required=True,
+ help='Role config file for how the Nexus role should be created.')
+@click.option(
+ '-s', '--settings', type=str, required=True,
+ help='Config file containing administrative settings.')
+@click.pass_context
+def role(ctx, config, settings):
+ """Create a Nexus role as defined by a role-config.yaml file."""
+ nexuscmd.create_roles(config, settings)
+
+
@nexus.group()
@click.pass_context
def docker(ctx):
return r.json()['data']['id']
def get_priv(self, name, priv):
+ """Get the ID for the privilege with the given name and privlege type."""
+ search_name = "{} - ({})".format(name, priv)
+ self.get_priv_by_name(search_name)
+
+ def get_priv_by_name(self, name):
"""Get the ID for the privilege with the given name."""
url = os.path.join(self.baseurl, 'privileges')
- search_name = "{} - ({})".format(name, priv)
privileges = requests.get(url, auth=self.auth, headers=self.headers).json()
for priv in privileges['data']:
- if priv['name'] == search_name:
+ if priv['name'] == name:
return priv['id']
raise LookupError("No privilege found named '{}'".format(name))
if role['name'] == name:
return role['id']
+ # If name is not found in names, check ids
+ for role in roles['data']:
+ if role['id'] == name:
+ return role['id']
+
raise LookupError("No role with name '{}'".format(name))
- def create_role(self, name, privs):
+ def create_role(self, name, privs, role_id="", description="", roles=[]):
"""Create a role with the given privileges."""
url = os.path.join(self.baseurl, 'roles')
role = {
'data': {
- 'id': name,
+ 'id': role_id if role_id else name,
'name': name,
- 'description': name,
+ 'description': description if description else name,
'privileges': privs,
- 'roles': [
- 'repository-any-read',
- ],
+ 'roles': ['repository-any-read'] + roles,
'sessionTimeout': 60,
}
}
json_data = json.dumps(role).encode(encoding='latin-1')
+ log.debug("Sending role {} to Nexus".format(json_data))
- r = requests.post(url, auth=self.auth, headers=self.headers, data=json_data)
+ r = requests.post(url, auth=self.auth, headers=self.headers,
+ data=json_data)
if r.status_code != requests.codes.created:
- raise Exception("Role not created for '{}', code '{}'".format(name, r.status_code))
+ if r.status_code == 400 and "errors" in r.json().keys():
+ error_msgs = ""
+ for error in r.json()["errors"]:
+ error_msgs += error["msg"] + "\n"
+ raise Exception("Role not created for '{}', code '{}', failed "
+ "with the following errors: {}".format(
+ name, r.status_code, error_msgs))
+ else:
+ raise Exception("Role not created for '{}', code '{}'".format(
+ role_id, r.status_code))
return r.json()['data']['id']
# Create Role
try:
role_id = _nexus.get_role(name)
- log.info('Creating {} role.'.format(role_id))
+ log.info('Role {} already exists.'.format(role_id))
except LookupError as e:
role_id = _nexus.create_role(name, privs)
# Create user
try:
_nexus.get_user(name)
- log.info('Creating {} user.'.format(name))
+ log.info('User {} already exists.'.format(name))
except LookupError as e:
_nexus.create_user(name, email, role_id, password, extra_privs)
config['base_groupId'], global_privs, config['email_domain'])
+def create_roles(config_file, settings_file):
+ """Create Nexus roles as defined by configuration file.
+
+ :arg str config: Configuration file containing role definitions that
+ will be used to create the new Nexus roles.
+ :arg str settings: Settings file containing administrative credentials and
+ information.
+ """
+ with open(config_file, 'r') as f:
+ config = yaml.safe_load(f)
+ with open(settings_file, 'r') as f:
+ settings = yaml.safe_load(f)
+
+ for setting in ['nexus', 'user', 'password']:
+ if setting not in settings:
+ log.error('{} needs to be defined in {}'.format(setting,
+ settings_file))
+ sys.exit(1)
+
+ _nexus = Nexus(settings['nexus'], settings['user'], settings['password'])
+
+ required_settings = ['name', 'roles']
+ for role in config:
+ for setting in required_settings:
+ if setting not in config[role]:
+ log.error('{} not defined for role {}. Please ensure that {} '
+ 'are defined for each role in {}'.format(
+ setting, role, required_settings, config_file))
+ sys.exit(1)
+
+ subrole_ids = []
+ for subrole in config[role]["roles"]:
+ subrole_id = _nexus.get_role(subrole)
+ subrole_ids.append(subrole_id)
+ config[role]["roles"] = subrole_ids
+
+ if "description" not in config[role]:
+ config[role]["description"] = config[role]["name"]
+
+ if "privileges" in config[role]:
+ priv_ids = []
+ for priv in config[role]["privileges"]:
+ priv_ids.append(_nexus.get_priv_by_name(priv))
+ config[role]["privileges"] = priv_ids
+ else:
+ config[role]["privileges"] = []
+
+ for role in config:
+ _nexus.create_role(config[role]["name"], config[role]["privileges"],
+ role, config[role]["description"],
+ config[role]["roles"])
+
+
def search(settings_file, url, repo, pattern):
"""Return of list of images in the repo matching the pattern.
--- /dev/null
+---
+features:
+ - |
+ Add "create role" subcommand for nexus, which enables users to create
+ Nexus roles outside of project creation.
--- /dev/null
+---
+lf-deployment:
+ name: LF Deployment Role
+ roles:
+ - nx-deployment
+ - analytics
+LF Deployment By Name:
+ name: LF Dep Role
+ privileges:
+ - Status - (read)
+ - Login to UI
+ roles:
+ - Nexus Deployment Role
+ - Analytics
+ description: "A role where I defined its contained roles by name"
--- /dev/null
+nexus: http://nexus.localhost
+user: admin
+password: admin123
--- /dev/null
+{
+ "data": [
+ {
+ "id": "1",
+ "resourceURI": "http://nexus.localhost/service/local/privileges/1",
+ "name": "Status - (read)",
+ "description": "Give permission to query the nexus server for it's status. This privilege is required by the anonymous user so that the UI can retrieve anonymous permissions on startup.",
+ "type": "method",
+ "userManaged": false,
+ "properties": [
+ {
+ "key": "method",
+ "value": "read"
+ },
+ {
+ "key": "permission",
+ "value": "nexus:status"
+ }
+ ]
+ },
+ {
+ "id": "2",
+ "resourceURI": "http://nexus.localhost/service/local/privileges/2",
+ "name": "Login to UI",
+ "description": "Give permission to allow a user to login to nexus.",
+ "type": "method",
+ "userManaged": false,
+ "properties": [
+ {
+ "key": "method",
+ "value": "read"
+ },
+ {
+ "key": "permission",
+ "value": "nexus:authentication"
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "data": [
+ {
+ "resourceURI": "http://nexus.localhost/service/local/roles/analytics",
+ "id": "analytics",
+ "name": "Analytics",
+ "description": "Gives access to Analytics",
+ "sessionTimeout": 0,
+ "privileges": [
+ "analytics-all"
+ ],
+ "userManaged": false
+ },
+ {
+ "resourceURI": "http://nexus.localhost/service/local/roles/nx-deployment",
+ "id": "nx-deployment",
+ "name": "Nexus Deployment Role",
+ "description": "Deployment role for Nexus",
+ "sessionTimeout": 0,
+ "roles": [
+ "ui-basic",
+ "anonymous"
+ ],
+ "privileges": [
+ "83"
+ ],
+ "userManaged": false
+ }
+ ]
+}
##############################################################################
"""Test nexus command."""
+import os
import re
+import pytest
+from lftools.nexus import cmd
from lftools.nexus import util
+FIXTURE_DIR = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), 'fixtures')
+
+
+@pytest.fixture
+def nexus2_obj_create(responses):
+ """Create the proper responses for the init of a nexus object"""
+ baseurl_endpoint = re.compile(".*nexus.*/service/local/repo_targets")
+ responses.add(responses.GET, baseurl_endpoint, status=200)
+
+
+@pytest.mark.datafiles(os.path.join(FIXTURE_DIR, 'nexus'))
+def test_create_roles(datafiles, responses, nexus2_obj_create):
+ """Test create_roles() method with good config."""
+ os.chdir(str(datafiles))
+ baseurl = "http://nexus.localhost/service/local/"
+ roles_url = baseurl + "roles"
+ privs_url = baseurl + "privileges"
+ role1_return = """{"data": {"id": "lf-deployment"}}"""
+ role2_return = """{"data": {"id": "LF Deployment By Name"}}"""
+
+ for _ in range(4): # Add response for each expected "get_role" call
+ with open("simplified_roles_list.json", "r") as roles_return:
+ responses.add(responses.GET, roles_url, roles_return.read())
+ for _ in range(2): # Add response for each expected "get_priv" call
+ with open("simplified_privs_list.json", "r") as privs_return:
+ responses.add(responses.GET, privs_url, privs_return.read())
+ responses.add(responses.POST, roles_url, role1_return, status=201)
+ responses.add(responses.POST, roles_url, role2_return, status=201)
+
+ cmd.create_roles("role_config-good.yaml", "settings.yaml")
+
+
def test_create_repo_target_regex():
"""Test create_repo_target_regex() command."""