Skip to content

Commit 0150551

Browse files
authored
Merge pull request #460 from NHSDigital/ADZ-3283_handle_company_apps
ADZ-3283 handle company apps
2 parents d078307 + 57a1edf commit 0150551

12 files changed

Lines changed: 73 additions & 95 deletions

File tree

ansible/collections/ansible_collections/nhsd/apigee/plugins/action/add_jwks_resource_url_to_app.py

Lines changed: 12 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
import requests
2-
import json
3-
import bisect
41
import copy
52

63
from ansible_collections.nhsd.apigee.plugins.module_utils.models.ansible.add_jwks_resource_url import (
@@ -13,7 +10,6 @@
1310
from ansible_collections.nhsd.apigee.plugins.module_utils import constants
1411

1512
ATTRIBUTE_NAME = "jwks-resource-url"
16-
DEVELOPER_DETAILS = "APIGEE_DEVELOPER_DETAILS"
1713

1814

1915
class ActionModule(ApigeeAction):
@@ -39,49 +35,24 @@ def run(self, tmp=None, task_vars=None):
3935
after["attributes"].append(jwks_attribute)
4036
after["attributes"] = sorted(after["attributes"], key=lambda attr: attr["name"])
4137

42-
developer_details = task_vars.get(DEVELOPER_DETAILS)
43-
if not developer_details:
44-
developer_details = []
45-
params = {"expand": True}
46-
url = (
47-
constants.APIGEE_BASE_URL
48-
+ f"organizations/{args.organization}/developers"
49-
)
50-
while True:
51-
resp = utils.get(url, args.access_token, params=params)
52-
if resp.get("failed"):
53-
return resp
54-
devs = resp["response"]["body"]["developer"]
55-
developer_details.extend(devs)
56-
if len(devs) == 1000:
57-
# last developer's ID as startKey will be included
58-
# in next request, so pop now to de-dupe.
59-
last_dev = developer_details.pop()
60-
params["startKey"] = last_dev["developerId"]
61-
else:
62-
break
63-
64-
try:
65-
developer_id = args._app_data["developerId"]
66-
developer_ids = [d["developerId"] for d in developer_details]
67-
i = bisect.bisect_left(developer_ids, developer_id)
68-
if i == len(developer_details):
69-
raise RuntimeError(f"Unable to find developer with id {developer_id}")
70-
except RuntimeError as e:
71-
return {"failed": True, "error": str(e)}
72-
73-
developer = developer_details[i]
74-
7538
delta = utils.delta(before, after)
7639
result = {
7740
"changed": bool(delta),
78-
"app": after,
79-
"developer": developer,
80-
"ansible_facts": {DEVELOPER_DETAILS: developer_details},
41+
"app": after
8142
}
8243

44+
company_exists = "companyName" in args._app_data.keys()
45+
developer_exists = "developerId" in args._app_data.keys()
46+
if developer_exists and not company_exists:
47+
owner = args._app_data["developerId"]
48+
elif company_exists and not developer_exists:
49+
owner = args._app_data["companyName"]
50+
else:
51+
return {"failed": True, "error": f"Invalid owner for app {args._app_data['appId']}"}
52+
53+
owner_endpoint = "companies" if company_exists else "developers"
8354
app_name = args._app_data["name"]
84-
app_path = f"organizations/{args.organization}/developers/{developer['email']}/apps/{app_name}/attributes"
55+
app_path = f"organizations/{args.organization}/{owner_endpoint}/{owner}/apps/{app_name}/attributes"
8556

8657
if diff_mode:
8758
result["diff"] = [

ansible/filter_plugins/apigee_helpers.py

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,21 @@ def apigee_apps_to_product_map(apps_list: List[dict], product_filter: str = None
2525
if api_product not in result:
2626
result[api_product] = []
2727

28+
company_exists = "companyName" in app.keys()
29+
developer_exists = "developerId" in app.keys()
30+
if developer_exists and not company_exists:
31+
owner = app["developerId"]
32+
elif company_exists and not developer_exists:
33+
owner = app["companyName"]
34+
else:
35+
raise RuntimeError(f"Invalid owner for app {app['appId']}")
36+
2837
result[api_product].append(
2938
dict(
3039
appId=app["appId"],
3140
appName=app["name"],
32-
developerId=app["developerId"],
41+
owner=owner,
42+
ownerEndpoint="companies" if company_exists else "developers",
3343
consumerKey=cred["consumerKey"],
3444
apiproduct=api_product
3545
)
@@ -39,6 +49,13 @@ def apigee_apps_to_product_map(apps_list: List[dict], product_filter: str = None
3949
return result
4050

4151

52+
def product_app_mapping_to_owner_display(dev_id_to_email: dict, product_app: dict):
53+
if product_app['ownerEndpoint'] == 'developers':
54+
return dev_id_to_email[product_app['owner']]
55+
else:
56+
return product_app['owner']
57+
58+
4259
def apigee_products_to_api_map(products: List[dict], proxy_filter: str = None):
4360

4461
result = dict()
@@ -73,28 +90,34 @@ def apigee_remove_proxy_from_product(product: dict, proxy_to_remove):
7390
return product
7491

7592

76-
def apigee_teams_map(teams: List[dict]):
93+
def apigee_team_to_admin(team):
94+
return next((attr.get('value') for attr in team['attributes'] if attr['name'] == 'ADMIN_EMAIL'), None)
95+
96+
97+
def apigee_teams_map(team_members: List[dict], teams: List[dict]):
98+
from collections import defaultdict
99+
joined = defaultdict(dict)
100+
for item in team_members + teams:
101+
joined[item['name']].update(item)
102+
full_teams = list(joined.values())
77103

78104
return {
79-
f"{team['id']}@devteam.apigee.io": {
80-
"contact": team['pointOfContact'],
81-
"members": list(mem['userId'] for mem in team.get('memberships', []))
105+
team['name']: {
106+
"contact": apigee_team_to_admin(team),
107+
"members": team['members']
82108
}
83-
for team in teams
109+
for team in full_teams
84110
}
85111

86112

87113
def apigee_teams_to_point_of_contact(teams: List[dict]):
88-
89-
return {
90-
f"{team['id']}@devteam.apigee.io": team['pointOfContact'] for team in teams
91-
}
114+
return {apigee_team_to_admin(team) for team in teams}
92115

93116

94117
def apigee_teams_to_members(teams: List[dict]):
95118

96119
return {
97-
f"{team['id']}@devteam.apigee.io": list(mem['userId'] for mem in team.get('memberships', [])) for team in teams
120+
team['owner']: team.get('members', []) for team in teams
98121
}
99122

100123

@@ -116,18 +139,16 @@ def apigee_product_developers(
116139
result[product_name] = []
117140

118141
for app in apps:
119-
developer = dev_id_to_email[app["developerId"]]
120-
121-
team = teams_map.get(developer, {})
122-
123142
entry = {
124-
"app": app["appName"],
125-
"developer": developer
143+
"app": app["appName"]
126144
}
127145

128-
if team:
146+
if app['ownerEndpoint'] == 'companies':
147+
team = teams_map.get(app.get("owner"), {})
129148
entry['developer'] = team['contact']
130149
entry['team'] = team['members']
150+
else:
151+
entry['developer'] = dev_id_to_email[app["owner"]]
131152

132153
result[product_name].append(entry)
133154

@@ -137,10 +158,6 @@ def apigee_product_developers(
137158

138159
return result
139160

140-
# return {
141-
# f"{team['id']}@devteam.apigee.io": list(mem['userId'] for mem in team.get('memberships', [])) for team in teams
142-
# }
143-
144161

145162
class FilterModule:
146163

@@ -154,5 +171,6 @@ def filters():
154171
'apigee_teams_to_point_of_contact': apigee_teams_to_point_of_contact,
155172
'apigee_teams_to_members': apigee_teams_to_members,
156173
'apigee_teams_map': apigee_teams_map,
157-
'apigee_product_developers': apigee_product_developers
174+
'apigee_product_developers': apigee_product_developers,
175+
'product_app_mapping_to_owner_display': product_app_mapping_to_owner_display
158176
}

ansible/get-developer-emails.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
- name: remove old pr portal apis
1+
- name: get developer emails
22
hosts: 127.0.0.1
33
connection: local
44
gather_facts: yes

ansible/roles/get-developer-emails/tasks/main.yml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,28 @@
4545

4646
- name: get teams
4747
uri:
48-
url: "https://apigee.com/consumers/api/providers/{{ audience_id }}/teams"
48+
url: "{{ companies_uri }}?expand=true"
4949
headers:
5050
Authorization: "Bearer {{ APIGEE_ACCESS_TOKEN }}"
5151
return_content: yes
5252
register: get_teams
5353

54+
- name: get team members
55+
uri:
56+
url: "{{ companies_uri }}/{{ item | replace(' ', '%20') }}/developers"
57+
headers:
58+
Authorization: "Bearer {{ APIGEE_ACCESS_TOKEN }}"
59+
return_content: yes
60+
register: get_team_members
61+
loop: "{{ get_teams.json.company | map(attribute='name') }}"
62+
63+
- name: setup developer team members map
64+
set_fact:
65+
team_members_map: "{{ get_team_members | json_query('results[*].{members: json.developer, name: item}') }}"
66+
5467
- name: setup developer teams map
5568
set_fact:
56-
teams_map: "{{ get_teams.json.data | apigee_teams_map }}"
69+
teams_map: "{{ get_team_members | json_query('results[*].{members: json.developer[*].email, name: item}') | apigee_teams_map(teams=get_teams.json.company) }}"
5770

5871
- name: "get apps"
5972
uri:

ansible/roles/get-developer-emails/tasks/output-emails.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22

3-
- debug: msg="{{ product_slug }} - {{ item.appName}} - {{ dev_id_to_email[item.developerId] }} - {{ apigee_teams_to_members[dev_id_to_email[item.developerId]] | default(dev_id_to_email[item.developerId]) }}"
3+
- debug: msg="{{ product_slug }} - {{ item.appName}} - {{ product_app_mapping_to_owner_display(dev_id_to_email, item) }} - {{ apigee_teams_to_members(teams_map)[product_app_mapping_to_owner_display(dev_id_to_email, item)] | default(product_app_mapping_to_owner_display(dev_id_to_email, item)) }}"
44
loop: "{{ product_app_map.get(product_slug, []) }}"
55
loop_control:
66
label: "{{ product_slug }} - {{ item.appName }} - {{ item.appId }}"

ansible/roles/get-developer-emails/vars/main.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ org_uri: "https://api.enterprise.apigee.com/v1/organizations/{{ APIGEE_ORGANIZAT
22
products_uri: "{{ org_uri }}/apiproducts"
33
apps_uri: "{{ org_uri }}/apps"
44
developers_uri: "{{ org_uri }}/developers"
5+
companies_uri: "{{ org_uri }}/companies"
56
retain_hours: "{{ (lookup('env', 'retain_hours') or 72) }}"
67
product_filter: "{{ lookup('env', 'PRODUCT_FILTER') }}"
78
portals_base_uri: "https://apigee.com/portals/api/sites"

ansible/roles/remove-old-pr-products/tasks/main.yml

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,4 @@
11

2-
- name: "get developers"
3-
uri:
4-
url: "{{ developers_uri }}?expand=true"
5-
headers:
6-
Authorization: "Bearer {{ APIGEE_ACCESS_TOKEN }}"
7-
return_content: yes
8-
register: get_developers
9-
10-
- name: "map developers"
11-
set_fact:
12-
dev_id_to_email: "{{ get_developers.json.developer | dict_list_to_map('developerId', 'email') }}"
13-
142
- name: "get apps"
153
uri:
164
url: "{{ apps_uri }}?expand=true"

ansible/roles/remove-old-pr-products/tasks/remove-product.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
- block:
4343
- name: "remove product apps {{ product_slug }}"
4444
uri:
45-
url: "{{ developers_uri }}/{{ dev_id_to_email[item.developerId] }}/apps/{{ item.appName | urlencode }}/keys/{{ item.consumerKey }}/apiproducts/{{ product_slug }}"
45+
url: "{{ org_uri }}/{{ item.ownerEndpoint }}/{{ item.owner | urlencode }}/apps/{{ item.appName | urlencode }}/keys/{{ item.consumerKey }}/apiproducts/{{ product_slug }}"
4646
method: DELETE
4747
headers:
4848
Authorization: "Bearer {{ APIGEE_ACCESS_TOKEN }}"
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
org_uri: "https://api.enterprise.apigee.com/v1/organizations/{{ APIGEE_ORGANIZATION }}"
22
products_uri: "{{ org_uri }}/apiproducts"
33
apps_uri: "{{ org_uri }}/apps"
4-
developers_uri: "{{ org_uri }}/developers"
54
retain_hours: "{{ (lookup('env', 'retain_hours') or 72) }}"

ansible/roles/remove-target-products/tasks/main.yml

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,3 @@
1-
- name: "get developers"
2-
uri:
3-
url: "{{ developers_uri }}?expand=true"
4-
headers:
5-
Authorization: "Bearer {{ APIGEE_ACCESS_TOKEN }}"
6-
return_content: yes
7-
register: get_developers
8-
9-
- name: "map developers"
10-
set_fact:
11-
dev_id_to_email: "{{ get_developers.json.developer | dict_list_to_map('developerId', 'email') }}"
121

132
- name: "get apps"
143
uri:

0 commit comments

Comments
 (0)