Skip to content

Commit

Permalink
Merge pull request #129 from EGI-ILM/master
Browse files Browse the repository at this point in the history
Issue #127
  • Loading branch information
tdviet authored Mar 4, 2022
2 parents 2696ef7 + 6cbc4d2 commit a5530cf
Showing 1 changed file with 83 additions and 46 deletions.
129 changes: 83 additions & 46 deletions fedcloudclient/endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"""

import os
import sys
from urllib import parse

import click
Expand All @@ -24,8 +25,18 @@
)
from fedcloudclient.shell import print_set_env_command

OPENSTACK_NOVA = "org.openstack.nova"
GOCDB_PUBLICURL = "https://goc.egi.eu/gocdbpi/public/"
TIMEOUT = 10
TLS_ERROR_MSG = "TLS error. IGTF certificates may not have been installed"
CONNECTION_ERROR_MSG = "Connection error"
SCOPED_TOKEN_ERROR_MSG = "Unable to get a scoped token"
UNSCOPED_TOKEN_ERROR_MSG = "Unable to get an unscoped token"


class TokenException(Exception):
"""Exception for Token related errors"""
# Basic exception. This should be extended


def get_sites():
Expand Down Expand Up @@ -118,7 +129,7 @@ def get_unscoped_token(os_auth_url, access_token):
return unscoped_token, protocol
except RuntimeError:
pass
raise RuntimeError("Unable to get a scoped token")
raise TokenException(SCOPED_TOKEN_ERROR_MSG)


def get_scoped_token(os_auth_url, access_token, project_id):
Expand All @@ -136,7 +147,7 @@ def get_scoped_token(os_auth_url, access_token, project_id):
request = requests.post(url, json=body)
# pylint: disable=no-member
if request.status_code != requests.codes.created:
raise RuntimeError("Unable to get a scoped token")
raise TokenException(SCOPED_TOKEN_ERROR_MSG)

return request.headers["X-Subject-Token"], protocol

Expand All @@ -156,12 +167,12 @@ def retrieve_unscoped_token(os_auth_url, access_token, protocol="openid"):
)
# pylint: disable=no-member
if request.status_code != requests.codes.created:
raise RuntimeError("Unable to get an unscoped token")
raise TokenException(UNSCOPED_TOKEN_ERROR_MSG)

return request.headers["X-Subject-Token"]


def get_projects(os_auth_url, unscoped_token):
def get_projects_from_single_site(os_auth_url, unscoped_token):
"""
Get list of projects from unscoped token
"""
Expand All @@ -171,49 +182,75 @@ def get_projects(os_auth_url, unscoped_token):
return request.json()["projects"]


def format_project_as_list(site_name, project):
"""
Format project data as a list
"""
return [
[project["id"], project["name"], project["enabled"], site_name]
]


def format_project_as_dict(site_name, project):
"""
Format project data as a dictionary
"""
return [
{
"project_id": project["id"],
"name": project["name"],
"enabled": project["enabled"],
"site": site_name,
}
]


def get_projects_from_sites(access_token, site):
"""
Get all projects from site(s) using access token
Get all projects from site(s) using access token, in the default output format (list)
"""
project_list = []
for site_ep in find_endpoint("org.openstack.nova", site=site):
os_auth_url = site_ep[2]
try:
unscoped_token, _ = get_unscoped_token(os_auth_url, access_token)
project_list.extend(
[
[p["id"], p["name"], p["enabled"], site_ep[0]]
for p in get_projects(os_auth_url, unscoped_token)
]
)
except (RuntimeError, requests.exceptions.ConnectionError):
pass
return project_list
return get_projects_from_sites_as_list(access_token, site)


def get_projects_from_sites_as_list(access_token, site):
"""
Get all projects from site(s) using access token, as a list
"""
return get_projects_from_sites_with_format(access_token, site, format_project_as_list)


def get_projects_from_sites_as_dict(access_token, site):
"""
Get all projects from site(s) using access token, as a dictionary
"""
return get_projects_from_sites_with_format(access_token, site, format_project_as_dict)

def get_projects_from_sites_dict(access_token, site):

def get_projects_from_sites_with_format(access_token, site, output_format_function):
"""
Get all projects as a dictionary from site(s) using access token
Get all projects from site(s) using access token
"""
project_list = []
for site_ep in find_endpoint("org.openstack.nova", site=site):
os_auth_url = site_ep[2]
project_error_list = []
for site_ep in find_endpoint(OPENSTACK_NOVA, site=site):
site_name = site_ep[0]
site_os_auth_url = site_ep[2]
try:
unscoped_token, _ = get_unscoped_token(os_auth_url, access_token)
project_list.extend(
[
{
"project_id": p["id"],
"name": p["name"],
"enabled": p["enabled"],
"site": site_ep[0],
}
for p in get_projects(os_auth_url, unscoped_token)
]
)
unscoped_token, _ = get_unscoped_token(site_os_auth_url, access_token)
for project in get_projects_from_single_site(site_os_auth_url, unscoped_token):
project_list.extend(output_format_function(site_name, project))
except TokenException:
# e.g. The user may have no permissions
pass
except requests.exceptions.SSLError:
project_error_list.append([site_name, TLS_ERROR_MSG])
except (requests.exceptions.ConnectionError, requests.exceptions.ReadTimeout):
# The site is unavailable e.g. HTTP 500
project_error_list.append([site_name, CONNECTION_ERROR_MSG])
except RuntimeError:
# Logging needed
pass
return project_list
return project_list, project_error_list


@click.group()
Expand All @@ -237,14 +274,14 @@ def projects(
if site in ALL_SITES_KEYWORDS or all_sites:
site = None

project_list = get_projects_from_sites(access_token, site)
project_list, project_error_list = get_projects_from_sites(access_token, site)
if len(project_list) > 0:
print(tabulate(project_list, headers=["id", "Name", "enabled", "site"]))
else:
print(f"Error: You probably do not have access to any project at site {site}")
print(
'Check your access token and VO memberships using "fedcloud token list-vos"'
)
print('Check your access token and VO memberships using "fedcloud token list-vos"')
if len(project_error_list) > 0:
print('[WARN] Sites not available: ', project_error_list, file=sys.stderr)


@endpoint.command()
Expand All @@ -265,7 +302,7 @@ def token(

# Getting sites from GOCDB
# assume first one is ok
site_ep = find_endpoint("org.openstack.nova", site=site).pop()
site_ep = find_endpoint(OPENSTACK_NOVA, site=site).pop()
os_auth_url = site_ep[2]
try:
scoped_token, _ = get_scoped_token(os_auth_url, access_token, project_id)
Expand All @@ -278,7 +315,7 @@ def token(
@all_site_params
@click.option(
"--service-type",
default="org.openstack.nova",
default=OPENSTACK_NOVA,
help="Service type in GOCDB",
show_default=True,
)
Expand All @@ -294,7 +331,7 @@ def token(
help="Monitoring status",
show_default=True,
)
def list(service_type, production, monitored, site, all_sites):
def endpoint_list(service_type, production, monitored, site, all_sites):
"""
List endpoints in site(s), will query GOCDB
"""
Expand Down Expand Up @@ -323,7 +360,7 @@ def env(

# Get the right endpoint from GOCDB
# assume first one is ok
site_ep = find_endpoint("org.openstack.nova", site=site).pop()
site_ep = find_endpoint(OPENSTACK_NOVA, site=site).pop()
os_auth_url = site_ep[2]

try:
Expand All @@ -335,5 +372,5 @@ def env(
print_set_env_command("OS_IDENTITY_PROVIDER", "egi.eu")
print_set_env_command("OS_PROTOCOL", protocol)
print_set_env_command("OS_ACCESS_TOKEN", access_token)
except RuntimeError:
raise SystemExit(f"Error: Unable to get Keystone token from site {site}")
except RuntimeError as runtime_error:
raise SystemExit(f"Error: Unable to get Keystone token from site {site}") from runtime_error

0 comments on commit a5530cf

Please sign in to comment.