Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix duplicate community v3 namespaces.
Browse files Browse the repository at this point in the history
No-Issue

Signed-off-by: James Tanner <tanner.jc@gmail.com>
jctanner committed Oct 3, 2023
1 parent 163d3dd commit de085d9
Showing 6 changed files with 117 additions and 5 deletions.
1 change: 1 addition & 0 deletions galaxy_ng/app/api/v1/viewsets/sync.py
Original file line number Diff line number Diff line change
@@ -46,5 +46,6 @@ def create(self, request):
serializer.is_valid(raise_exception=True)
kwargs = dict(serializer.validated_data)
logger.debug(f'REQUEST kwargs: {kwargs}')
print(f'REQUEST kwargs: {kwargs}')
task_id = self.legacy_dispatch(legacy_sync_from_upstream, kwargs=kwargs)
return Response({'task': task_id})
3 changes: 3 additions & 0 deletions galaxy_ng/app/utils/galaxy.py
Original file line number Diff line number Diff line change
@@ -130,6 +130,7 @@ def get_namespace_owners_details(baseurl, ns_id):
owners = []
next_owners_url = baseurl + f'/api/v1/namespaces/{ns_id}/owners/'
while next_owners_url:
print(next_owners_url)
o_data = safe_fetch(next_owners_url).json()
for owner in o_data['results']:
owners.append(owner)
@@ -155,6 +156,7 @@ def upstream_namespace_iterator(
if not baseurl.rstrip().endswith('/api/v1/namespaces'):
baseurl = baseurl.rstrip() + '/api/v1/namespaces'
logger.info(f'baseurl2: {baseurl}')
print(f'NS ITERATOR BASEURL {baseurl}')

# normalize the upstream url
parsed = urlparse(baseurl)
@@ -413,6 +415,7 @@ def upstream_role_iterator(
if baseurl is None or not baseurl:
baseurl = 'https://old-galaxy.ansible.com/api/v1/roles'
logger.info(f'baseurl2: {baseurl}')
print('ROLE ITERATOR BASEURL {baseurl}')

# normalize the upstream url
parsed = urlparse(baseurl)
30 changes: 28 additions & 2 deletions galaxy_ng/social/__init__.py
Original file line number Diff line number Diff line change
@@ -63,9 +63,14 @@ def do_auth(self, access_token, *args, **kwargs):
v3_namespace, v3_namespace_created = \
self.handle_v3_namespace(auth_response, email, login, gid)

print('-' * 100)
print(f'{login} v3 namespace: {v3_namespace}')
print('-' * 100)

# create a legacynamespace and bind to the v3 namespace?
legacy_namespace, legacy_namespace_created = \
self._ensure_legacynamespace(login, v3_namespace)
if v3_namespace:
legacy_namespace, legacy_namespace_created = \
self._ensure_legacynamespace(login, v3_namespace)

return auth_response

@@ -82,15 +87,18 @@ def handle_v3_namespace(self, session_user, session_email, session_login, github
namespace_name = self.transform_namespace_name(session_login)

logger.debug(f'TRANSFORMED NAME: {namespace_name}')
print(f'TRANSFORMED NAME: {namespace_name}')

if not self.validate_namespace_name(namespace_name):
logger.debug(f'DID NOT VALIDATE NAMESPACE NAME: {namespace_name}')
print(f'DID NOT VALIDATE NAMESPACE NAME: {namespace_name}')
return False, False

# does the namespace already exist?
found_namespace = Namespace.objects.filter(name=namespace_name).first()

logger.debug(f'FOUND NAMESPACE: {found_namespace}')
print(f'FOUND NAMESPACE: {found_namespace}')

# is it owned by this userid?
if found_namespace:
@@ -101,6 +109,24 @@ def handle_v3_namespace(self, session_user, session_email, session_login, github
if session_user in owners:
return found_namespace, False

# FIXME - make one from the transformed name?
if not found_namespace:
namespace, namespace_created = self._ensure_namespace(namespace_name, session_user)
return namespace, namespace_created

# short circuit if the user does own at least one namespace ...
owned_namespaces = rbac.get_owned_v3_namespaces(session_user)
logger.debug(f'FOUND USER OWNED NAMESPACES: {owned_namespaces}')
print(f'FOUND USER OWNED NAMESPACES: {owned_namespaces}')
if owned_namespaces:
# does one resemble the desired namespace name?
owned_namespaces = sorted(owned_namespaces)
for ns in owned_namespaces:
if ns.name.startswith(namespace_name):
logger.debug(f'MATCHED NS OWNED BY {session_user}: {ns} {ns.name}')
return ns, False
return None, False

# should always have a namespace ...
if found_namespace:
logger.debug(
3 changes: 2 additions & 1 deletion galaxy_ng/tests/integration/api/test_community.py
Original file line number Diff line number Diff line change
@@ -166,7 +166,7 @@ def test_me_social_with_v1_synced_user(ansible_config):
)

# v1 sync the user's roles and namespace ...
pargs = json.dumps({"github_user": username, "limit": 1}).encode('utf-8')
pargs = json.dumps({"github_user": username, "limit": 1, "baseurl": "https://old-galaxy.ansible.com"}).encode('utf-8')
resp = admin_client('/api/v1/sync/', method='POST', args=pargs)
wait_for_v1_task(resp=resp, api_client=admin_client)

@@ -430,6 +430,7 @@ def test_list_collections_social(ansible_config):
validate_json(instance=resp.json(), schema=schema_objectlist)


@pytest.mark.skip(reason='switchover is complete')
@pytest.mark.deployment_community
def test_v1_sync_with_user_and_limit(ansible_config):
"""" Tests if v1 sync accepts a user&limit arg """
2 changes: 1 addition & 1 deletion galaxy_ng/tests/integration/cli/test_community_sync.py
Original file line number Diff line number Diff line change
@@ -58,7 +58,7 @@ def test_community_collection_download_count_sync(ansible_config):
remotes = dict((x['name'], x) for x in resp['results'])
community_remote_config = {
'name': 'community',
'url': 'https://galaxy.ansible.com/',
'url': 'https://old-galaxy.ansible.com/',
'sync_dependencies': False,
'requirements_file': json.dumps({'collections': ['.'.join(list(sync_collection))]}),
}
Original file line number Diff line number Diff line change
@@ -241,15 +241,35 @@ def test_social_user_with_reclaimed_login(ansible_config):
# the "bar" namespace will not belong to them
# do they own -any- namespaces?

admin_config = ansible_config("admin")
admin_client = get_client(
config=admin_config,
request_token=False,
require_auth=True
)

ga = GithubAdminClient()
ga.delete_user(login='Wilk42')
ga.delete_user(login='sean-m-sullivan')
cleanup_social_user('Wilk42', ansible_config)
cleanup_social_user('sean-m-sullivan', ansible_config)
cleanup_social_user('sean_m_sullivan', ansible_config)
cleanup_social_user('sean-m-sullivan@redhat.com', ansible_config)

default_cfg = extract_default_config(ansible_config)

nsmap = {}
next_url = '/api/v3/namespaces/'
while next_url:
resp = admin_client(next_url)
nsmap.update(dict((x['name'], x) for x in resp['data']))
next_url = resp['links']['next']
for nsname, nsdata in nsmap.items():
if not nsname.lower().startswith('sean_m') and not nsname.lower().startswith('wilk42'):
continue
cleanup_social_user(nsname, ansible_config)
cleanup_namespace(nsname, api_client=admin_client)

old_login = 'Wilk42'
email = 'sean-m-sullivan@redhat.com'
user_a = ga.create_user(login=old_login, email=email)
@@ -258,7 +278,6 @@ def test_social_user_with_reclaimed_login(ansible_config):

# login once to make user
with SocialGithubClient(config=user_a) as client:

a_resp = client.get('_ui/v1/me/')
ns_resp = client.get('_ui/v1/my-namespaces/')
ns_ds = ns_resp.json()
@@ -480,3 +499,65 @@ def test_rbac_utils_get_owned_v3_namespaces(ansible_config):
@pytest.mark.deployment_community
def test_community_tools_urls(ansible_config):
pass

@pytest.mark.deployment_community
def test_social_auth_no_duplicated_namespaces(ansible_config):

# https://issues.redhat.com/browse/AAH-2729

ga = GithubAdminClient()
ga.delete_user(login='Wilk42')
ga.delete_user(login='sean-m-sullivan')
cleanup_social_user('sean-m-sullivan', ansible_config)
cleanup_social_user('Wilk42', ansible_config)
cleanup_social_user('wilk42', ansible_config)
cleanup_social_user('sean-m-sullivan@findme.net', ansible_config)
cleanup_social_user('30054029@GALAXY.GITHUB.UNVERIFIED.COM', ansible_config)

default_cfg = extract_default_config(ansible_config)

admin_config = ansible_config("admin")
admin_client = get_client(
config=admin_config,
request_token=False,
require_auth=True
)

# find all the sean_m* namespaces and clean them up ...
nsmap = {}
next_url = '/api/v3/namespaces/'
while next_url:
resp = admin_client(next_url)
nsmap.update(dict((x['name'], x) for x in resp['data']))
next_url = resp['links']['next']
for nsname, nsdata in nsmap.items():
if not nsname.startswith('sean_m') and not nsname.startswith('wilk42'):
continue
cleanup_social_user(nsname, ansible_config)
cleanup_namespace(nsname, api_client=admin_client)

# make sean_m_sullivan namespace with no owners?
api_prefix = admin_client.config.get("api_prefix").rstrip("/")
payload = {'name': 'sean_m_sullivan', 'groups': []}
resp = admin_client(f'{api_prefix}/v3/namespaces/', args=payload, method='POST')

# make sean-m-sullivan on github
ga.delete_user(login='sean-m-sullivan')
sean = ga.create_user(login='sean-m-sullivan', email='sean@findme.net', uid=30054029)
sean['username'] = sean['login']
sean.update(default_cfg)

# login 10 times ...
for x in range(0, 10):
with SocialGithubClient(config=sean) as client:
client.get('_ui/v1/me/')

# check to make sure only the one ns was created ...
nsmap = {}
next_url = '/api/v3/namespaces/'
while next_url:
resp = admin_client(next_url)
nsmap.update(dict((x['name'], x) for x in resp['data']))
next_url = resp['links']['next']
sean_namespaces = sorted([x for x in nsmap.keys() if x.startswith('sean_m')])
assert sean_namespaces == ['sean_m_sullivan', 'sean_m_sullivan0']

0 comments on commit de085d9

Please sign in to comment.