From 7d675795aa169000b872c31515ac50b47f189def Mon Sep 17 00:00:00 2001
From: Mats Rynge
Date: Tue, 25 Nov 2025 12:45:28 -0800
Subject: [PATCH] OSPool ACCESS/AMIE: factored out OSGConnect
---
opensciencegrid/access-amie/lib/CLI.py | 61 +++------
opensciencegrid/access-amie/lib/Main.py | 82 ++++++------
opensciencegrid/access-amie/lib/OSGConnect.py | 117 ------------------
3 files changed, 54 insertions(+), 206 deletions(-)
delete mode 100644 opensciencegrid/access-amie/lib/OSGConnect.py
diff --git a/opensciencegrid/access-amie/lib/CLI.py b/opensciencegrid/access-amie/lib/CLI.py
index a3fe69af..381c0aed 100644
--- a/opensciencegrid/access-amie/lib/CLI.py
+++ b/opensciencegrid/access-amie/lib/CLI.py
@@ -9,7 +9,6 @@
from amieclient.packet import NotifyPersonIDs
from AMIE import AMIE
-from OSGConnect import OSGConnect
log_config = {
"version": 1,
@@ -50,7 +49,6 @@ def main():
config = configparser.ConfigParser()
config.read('/opt/access-amie/etc/access-amie.conf')
amie = AMIE(config)
- connect = OSGConnect(config)
parser = argparse.ArgumentParser(prog='access-amie')
# parser.add_argument('--foo', action='store_true', help='foo help')
@@ -58,24 +56,27 @@ def main():
# create the parser for the "project-created" command
parser_pcreated = subparsers.add_parser('project-created',
- help='Use this when a ACCESS requested project and PI has been set up in OSGConnect')
+ help='Use this when a ACCESS requested project and PI has been set up in OSPool')
parser_pcreated.add_argument('--project', required=True, help='Project in the form of TG-XXXXXXXX')
- parser_pcreated.add_argument('--pi-username', required=True, help='OSGConnect username of the PI')
+ parser_pcreated.add_argument('--pi-username', required=True, help='OSPool username of the PI')
+ parser_pcreated.add_argument('--pi-uid', required=True, help='OSPool uid of the PI')
parser_pcreated.set_defaults(func=project_created)
# create the parser for the "account-created" command
parser_acreated = subparsers.add_parser('account-created',
- help='Use this when a ACCESS requested user account been set up in OSGConnect')
+ help='Use this when a ACCESS requested user account been set up in OSPool')
parser_acreated.add_argument('--global-id', required=True, help='ACCESS Global ID')
parser_acreated.add_argument('--project', required=True, help='Project in the form of TG-XXXXXXXX')
- parser_acreated.add_argument('--username', required=True, help='OSGConnect username')
+ parser_acreated.add_argument('--ospool-username', required=True, help='OSPool username')
+ parser_acreated.add_argument('--ospool-uid', required=True, help='OSPool uid')
parser_acreated.set_defaults(func=account_created)
# create the parser for the "account-move" command
parser_amove = subparsers.add_parser('account-move',
- help='Move an existing account to a new OSGConnect uid/username')
+ help='Move an existing account to a new OSPool uid/username')
parser_amove.add_argument('--access-person-id', required=True, help='ACCESS global person id')
- parser_amove.add_argument('--connect-username', required=True, help='Target user in OSGConnect')
+ parser_amove.add_argument('--ospool-username', required=True, help='Target user in OSPool')
+ parser_amove.add_argument('--ospool-uid', required=True, help='Target uid in OSPool')
parser_amove.set_defaults(func=account_move)
# create the parser for the "account-park" command
@@ -91,19 +92,6 @@ def main():
def project_created(args):
- # Ensure that the project and user exists in OSGConnect, we have
- # a corresponding parked AMIE rpc packet, and if so send the
- # notify_project_create package to AMIE
-
- try:
- project = connect.project(args.project)
- pi = connect.user(args.pi_username)
- uid = pi['unix_id']
- # for testing - how should we switch to this?
- # uid = re.sub('foo', '', args.pi_username)
- except Exception as e:
- log.exception(e)
- sys.exit(1)
# find the parked packet
rpc = None
@@ -118,7 +106,7 @@ def project_created(args):
# construct a NotifyProjectCreate(NPC) packet.
npc = rpc.reply_packet()
npc.ProjectID = args.project # local project ID
- npc.PiPersonID = uid # local person ID for the pi
+ npc.PiPersonID = args.pi_uid # local person ID for the pi
npc.PiRemoteSiteLogin = args.pi_username # local username
# send the NPC
@@ -129,19 +117,6 @@ def project_created(args):
def account_created(args):
- # Ensure that the user exists in OSGConnect, we have
- # a corresponding parked AMIE rac packet, and if so send the
- # notify_account_create package to AMIE
-
- try:
- project = connect.project(args.project)
- pi = connect.user(args.username)
- uid = pi['unix_id']
- # for testing - how should we switch to this?
- # uid = re.sub('foo', '', args.username)
- except Exception as e:
- log.exception(e)
- sys.exit(1)
# find the parked packet
rac = None
@@ -162,8 +137,8 @@ def account_created(args):
# construct a NotifyAccountCreate(NAC) packet.
nac = rac.reply_packet()
nac.ProjectID = args.project # local project ID
- nac.UserPersonID = uid # local person ID for the pi
- nac.UserRemoteSiteLogin = args.username # local username
+ nac.UserPersonID = args.ospool_uid # local person ID for the pi
+ nac.UserRemoteSiteLogin = args.ospool_username # local username
# send the NPC
amie.send_packet(nac)
@@ -173,22 +148,14 @@ def account_created(args):
def account_move(args):
- # Ensure the new uid/username exist in OSGConnect. No verification
- # on the old uid.
-
- try:
- user = connect.user(args.connect_username)
- except Exception as e:
- log.exception(e)
- sys.exit(1)
# construct a NotifyPersonIDs packet.
npi = NotifyPersonIDs(
originating_site_name="OSG"
)
npi.PersonID = args.access_person_id
- npi.PrimaryPersonID = user['unix_id']
- npi.PersonIdList = [user['unix_id']]
+ npi.PrimaryPersonID = args.ospool_uid
+ npi.PersonIdList = [args.ospool_uid]
# remove old ones
npi.RemoveResourceList = ['grid1.osg.xsede']
npi.ResourceLogin = [{
diff --git a/opensciencegrid/access-amie/lib/Main.py b/opensciencegrid/access-amie/lib/Main.py
index 0e490abf..7317c861 100644
--- a/opensciencegrid/access-amie/lib/Main.py
+++ b/opensciencegrid/access-amie/lib/Main.py
@@ -53,7 +53,6 @@
class Main():
config = None
amie = None
- connect = None
freshdesk = None
def __init__(self):
@@ -93,23 +92,22 @@ def request_project_create(self, packet):
subject = f'OSG/ACCESS - create PI account to activate your allocation TG-{grant_number}'
body = f'''Thank you for your interest in using OSPool resources via an ACCESS allocation.
-When you are ready to use your OSPool allocation, you (the allocation PI) need an account
-with the OSG Connect service.
+When you are ready to use your OSPool allocation, you (the allocation PI) need an OSPool account.
-If you already have an OSG Connect user profile:
-You can check by trying to ‘Log In’ via the osgconnect.net website using your institutional
-identity. If you are able to view your user Profile and are ready to charge OSPool usage against
-your ACCESS allocation, please send an email to support@osg-htc.org, to request that your
+If you already have an OSPool account:
+You can check by trying to ‘Log In’ to https://registry.cilogon.org/registry/co_dashboards/dashboard/co:7
+using your institutional identity. If you are able to view your user Profile and are ready to charge
+OSPool usage against your ACCESS allocation, please send an email to support@osg-htc.org, to request that your
user account be associated with the appropriate allocation charge code (e.g. TG-{grant_number}).
-If you do not yet have an OSG Connect user profile:
-Please ‘Sign Up’ for an account at https://connect.osg-htc.org/signup using your institutional
-identity, and copy the below into the Comments field before submitting your Sign Up request.
+If you do not yet have an OSPool account:
+Please ‘Sign Up’ for an account at https://portal.osg-htc.org/application , and copy the below into
+the additional information field before submitting your request.
@@ -187,41 +185,41 @@ def request_account_create(self, packet):
project_id = packet.ProjectID
# RACs are also used to reactivate accounts, so if the account already exists, just set it active
- if user_person_id and len(user_person_id) > 1:
- try:
- user = self.connect.user(user_person_id)
-
- # ensure emails match
- if user_email == user['email']:
- # construct a NotifyAccountCreate(NAC) packet.
- nac = packet.reply_packet()
- nac.UserRemoteSiteLogin = user['unix_name'] # local login for the User on the resource
- nac.UserPersonID = user_person_id # local person ID for the User
- self.amie.send_packet(nac)
- return
- except Exception:
- # unable to find/process the user - fall back to facilitators
- pass
-
- subject = f'OSG/ACCESS - create an account on OSG Connect'
+ #if user_person_id and len(user_person_id) > 1:
+ # try:
+ # user = self.connect.user(user_person_id)
+ #
+ # # ensure emails match
+ # if user_email == user['email']:
+ # # construct a NotifyAccountCreate(NAC) packet.
+ # nac = packet.reply_packet()
+ # nac.UserRemoteSiteLogin = user['unix_name'] # local login for the User on the resource
+ # nac.UserPersonID = user_person_id # local person ID for the User
+ # self.amie.send_packet(nac)
+ # return
+ # except Exception:
+ # # unable to find/process the user - fall back to facilitators
+ # pass
+
+ subject = f'OSG/ACCESS - create an OSPool account'
body = f'''Thank you for your application for an OSG account via an ACCESS allocation. When you
-are ready to use your allocation, you will need an account with the OSG Connect service.
+are ready to use your allocation, you will need an OSPool account.
-If you already have an OSG Connect user profile:
-You can double check by trying to ‘Log In’ via the https://connect.osg-htc.org/ website using your institutional identity.
-If you are able to view your user Profile without needing to ‘Sign Up’ and are ready to charge OSPool usage
-against your ACCESS allocation, please send an email to support@osg-htc.org, to request that your
-user account be associated with the appropriate allocation charge code (e.g. {project_id}).
+If you already have an OSPool account:
+You can double check by trying to ‘Log In’ to https://registry.cilogon.org/registry/co_dashboards/dashboard/co:7
+using your institutional identity. If you are able to view your user Profile without needing to ‘Sign Up’ and
+are ready to charge OSPool usage against your ACCESS allocation, please send an email to support@osg-htc.org,
+to request that your user account be associated with the appropriate allocation charge code (e.g. {project_id}).
-If you do not yet have an OSG Connect user profile:
-Please ‘Sign Up’ for an account at https://connect.osg-htc.org/signup using your institutional identity, and
-copy the below into the Comments field before submitting your ‘Sign Up’ request:
+If you do not yet have an OSPool account:
+Please ‘Sign Up’ for an account at https://portal.osg-htc.org/application , and copy the below into
+the additional information field before submitting your request.
@@ -309,12 +307,12 @@ def request_project_inactivate(self, packet):
resource = packet.ResourceList[0]
project_id = packet.ProjectID
- log.info('Deactivating {}'.format(project_id))
- try:
- self.connect.remove_all_users(project_id)
- except:
- # project might not exist
- pass
+ #log.info('Deactivating {}'.format(project_id))
+ #try:
+ # self.connect.remove_all_users(project_id)
+ #except:
+ # # project might not exist
+ # pass
nai = packet.reply_packet()
self.amie.send_packet(nai)
diff --git a/opensciencegrid/access-amie/lib/OSGConnect.py b/opensciencegrid/access-amie/lib/OSGConnect.py
deleted file mode 100644
index 700d9d48..00000000
--- a/opensciencegrid/access-amie/lib/OSGConnect.py
+++ /dev/null
@@ -1,117 +0,0 @@
-#!/usr/bin/python3
-
-import configparser
-import json
-import logging
-import requests
-
-log = logging.getLogger('accessamie')
-
-
-# This class is mostly used with data from the ACCESS AMIE system, and thus
-# there is a built in flexibility here to deal with the fact that sometimes
-# we get local username, and some time local uid, from AMIE. When a "user"
-# is specified in this interface, it can be either username or uid, and it
-# will be interpreted based on if is numeric (uid), or alphanumeric.
-# (username). If we have a uid, it will be quickly mapped to a username.
-
-class OSGConnect():
- config = None
- base_url = None
- token = None
-
- def __init__(self, config):
- self.config = config
- self.base_url = config.get('connect', 'url')
- self.token = config.get('connect', 'token')
-
- # def update_user(self, username, ...):
-
- def _get(self, path):
- if path[0] != '/':
- path = '/{}'.format(path)
- resp = requests.get('{}{}?token={}'.format(self.base_url, path, self.token))
- if resp.status_code != 200:
- raise RuntimeError('Error {} from: {}{}'.format(resp.status_code, self.base_url, path))
- return resp.json()
-
- def _post(self, path, data):
- if path[0] != '/':
- path = '/{}'.format(path)
- headers = {'Content-type': 'application/json', 'Accept': 'application/json'}
- resp = requests.post('{}{}?token={}'.format(self.base_url, path, self.token), json=data, headers=headers)
- if resp.status_code != 200:
- raise RuntimeError('Error {} from: {}{}'.format(resp.status_code, self.base_url, path))
- return resp.json()
-
- def _put(self, path, data):
- if path[0] != '/':
- path = '/{}'.format(path)
- headers = {'Content-type': 'application/json', 'Accept': 'application/json'}
- resp = requests.put('{}{}?token={}'.format(self.base_url, path, self.token), json=data, headers=headers)
- if resp.status_code != 200:
- raise RuntimeError('Error {} from: {}{}'.format(resp.status_code, self.base_url, path))
- return resp.raw
-
- def _delete(self, path):
- if path[0] != '/':
- path = '/{}'.format(path)
- resp = requests.delete('{}{}?token={}'.format(self.base_url, path, self.token))
- if resp.status_code != 200:
- raise RuntimeError('Error {} from: {}{}'.format(resp.status_code, self.base_url, path))
- return resp.raw
-
- def _uid_to_username(self, uid):
- data = self._get('/users')
- for item in data['items']:
- if str(uid) == str(item['metadata']['unix_id']):
- return item['metadata']['unix_name']
- raise RuntimeError('User not found')
-
- def project(self, name):
- data = self._get('/groups/root.osg.{}'.format(name))
- if 'metadata' not in data:
- raise RuntimeError("Group does not exist in OSGConnect")
- return data['metadata']
-
- def user(self, id):
- # id can be uid or username
- if str(id).isdecimal():
- username = self._uid_to_username(id)
- else:
- username = id
-
- data = self._get('/users/{}'.format(username))
- if 'metadata' not in data:
- raise RuntimeError("User does not exist in OSGConnect")
- return data['metadata']
-
- def add_user_to_project(self, project, user):
- # look up the user
- username = self.user(user)['unix_name']
- data = {
- 'group_membership': {
- 'state': 'active'
- }
- }
- self._put('/groups/root.osg.{}/members/{}'.format(project, username), data)
- return True
-
- def remove_user_from_project(self, project, user):
- # look up the user
- username = self.user(user)['unix_name']
- self._delete('/users/{}/groups/root.osg.{}'.format(username, project))
- return True
-
-
-if __name__ == '__main__':
- config = configparser.ConfigParser()
- config.read('/opt/access-amie/etc/access-amie.conf')
- connect = OSGConnect(config)
- assert connect._uid_to_username(42312) == 'rynge', 'UID 42312 is user rynge'
- assert connect.user('42312')['unix_name'] == 'rynge', 'User rynge found'
- assert connect.user('rynge')['unix_id'] == 42312, 'User rynge found'
- assert connect.project('OSG-Staff')['unix_id'] == 7158, 'GID 7158 is OSG-Staff'
- assert connect.remove_user_from_project('OSGUserTrainingPilot', 'rynge'), 'Removing user from project'
- assert connect.add_user_to_project('OSGUserTrainingPilot', 'rynge'), 'Adding user to project'
- print('All tests passed')