diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2921933..cd2436f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,11 +10,14 @@ on: jobs: test: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: matrix: python: - - 3.8 + - "3.10" + - "3.11" + - "3.12" + - "3.13" steps: - uses: actions/checkout@v4 - name: Set up Python 3.x diff --git a/chi/context.py b/chi/context.py index 150d6fb..215332b 100644 --- a/chi/context.py +++ b/chi/context.py @@ -31,6 +31,15 @@ EDGE_RESOURCE_API_URL = os.getenv( "EDGE_RESOURCE_API_URL", "https://chameleoncloud.org/edge-hw-discovery/devices" ) +DEFAULT_CLIENT_ID = "chi-cli-device-token" +DEFAULT_DISCOVERY_ENDPOINT = ( + "https://auth.chameleoncloud.org/auth/realms/chameleon" + "/.well-known/openid-configuration" +) +DEFAULT_PROTOCOL = "openid" +DEFAULT_IDENTITY_PROVIDER = "chameleon" +DEFAULT_SCOPE = "openid" +DEFAULT_PROJECT_DOMAIN_NAME = "chameleon" def default_key_name(): @@ -74,6 +83,7 @@ def default_key_name(): _session = None _sites = {} _lease_id = None +_device_auth = False version = "1.1" @@ -366,7 +376,7 @@ def use_site(site_name: str) -> None: Args: site_name (str): The name of the site, e.g., "CHI@UC". """ - global _sites + global _sites, _session if not _sites: try: _sites = list_sites() @@ -392,6 +402,9 @@ def use_site(site_name: str) -> None: ) ) + _session = None + + set("project_domain_name", DEFAULT_PROJECT_DOMAIN_NAME) set("auth_url", f"{site['web']}:5000/v3") set("region_name", site["name"]) @@ -404,6 +417,25 @@ def use_site(site_name: str) -> None: print("\n".join(output)) +def use_device_auth(enable: bool = True) -> None: + """Enable or disable device authorization for subsequent sessions. + + Call `use_device_auth()` before creating a session (or before `use_site`) + to opt into the device authorization flow. Pass `False` to disable. + + Args: + enable (bool): True to enable device auth, False to disable. + """ + global _device_auth, _session + _device_auth = bool(enable) + + _session = None + if _device_auth: + print("Device authorization enabled.") + else: + print("Device authorization disabled.") + + def choose_site(default: str = None) -> None: """ Displays a dropdown menu to select a chameleon site. @@ -650,13 +682,42 @@ def session(): Returns: keystoneauth1.session.Session: the authentication session object. """ - global _session + global _session, _device_auth if not _session: - auth = loading.load_auth_from_conf_options(cfg.CONF, CONF_GROUP) - sess = SessionLoader().load_from_conf_options(cfg.CONF, CONF_GROUP, auth=auth) - _session = loading.load_adapter_from_conf_options( - cfg.CONF, CONF_GROUP, session=sess - ) + if _device_auth: + auth_url = get("auth_url") + try: + from ccauth.plugin import ChameleonDeviceAuth + except ImportError as e: + raise CHIValueError( + "Device auth requested but package 'ccauth' is not installed." + " Install 'ccauth' to use device authorization." + ) from e + + plugin = ChameleonDeviceAuth( + auth_url=auth_url, + identity_provider=DEFAULT_IDENTITY_PROVIDER, + protocol=DEFAULT_PROTOCOL, + client_id=DEFAULT_CLIENT_ID, + discovery_endpoint=DEFAULT_DISCOVERY_ENDPOINT, + scope=DEFAULT_SCOPE, + project_name=get("project_name"), + project_domain_name=get("project_domain_name"), + ) + sess = SessionLoader().load_from_conf_options( + cfg.CONF, CONF_GROUP, auth=plugin + ) + _session = loading.load_adapter_from_conf_options( + cfg.CONF, CONF_GROUP, session=sess + ) + else: + auth = loading.load_auth_from_conf_options(cfg.CONF, CONF_GROUP) + sess = SessionLoader().load_from_conf_options( + cfg.CONF, CONF_GROUP, auth=auth + ) + _session = loading.load_adapter_from_conf_options( + cfg.CONF, CONF_GROUP, session=sess + ) return _session @@ -671,8 +732,10 @@ def reset(): """ global _session global _sites + global _device_auth _session = None _sites = {} + _device_auth = False cfg.CONF.reset() _set_auth_plugin( os.getenv("OS_AUTH_TYPE", os.getenv("OS_AUTH_METHOD", DEFAULT_AUTH_TYPE)) diff --git a/requirements.txt b/requirements.txt index 9d2a10b..6ab65f2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,11 +10,11 @@ python-manilaclient python-neutronclient python-novaclient python-swiftclient -python-zunclient +git+https://github.com/chameleoncloud/python-zunclient ipython ipydatagrid ipywidgets networkx matplotlib pandas - +git+https://github.com/ChameleonCloud/ccauth.git