Skip to content

Commit c3b9ae9

Browse files
stevsmitSteven Smith
andauthored
Updates the script to cycle org applications (quay#1200)
Co-authored-by: Steven Smith <[email protected]>
1 parent 9e32e61 commit c3b9ae9

File tree

1 file changed

+60
-22
lines changed

1 file changed

+60
-22
lines changed

modules/automating-quay-using-the-api.adoc

Lines changed: 60 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@
22
[id="automating-quay-using-the-api"]
33
= Automating {productname} processes by using the API
44

5-
With the API, {productname} administrators and users with access to the API can automate repetitive tasks such as repository management or image pruning. The following example shows you how you might use a Python script and a cron job to to automate image pruning.
5+
With the API, {productname} administrators and users with access to the API can automate repetitive tasks such as repository management or image pruning.
6+
7+
The following example shows you how you might use a Python script and a cron job to automate the deletion of OAuth 2 applications _except_ the administrator's token. This might be useful if you want to ensure an application associated with an OAuth 2 access token is cycled after a certain period of time.
68

79
.Prerequisites
810

911
* You have access to the {productname} API, which entails having already created an OAuth 2 access token.
1012
* You have set `BROWSER_API_CALLS_XHR_ONLY: false` in your `config.yaml` file.
1113
* You have installed the Python `requests` library using.
1214
* You have enabled cron jobs on your machine.
15+
* You have created several organization applications, including one that will not be deleted.
1316
1417
.Procedure
1518

@@ -23,38 +26,73 @@ import requests <1>
2326
# Hard-coded values
2427
API_BASE_URL = "http://<quay-server.example.com>/api/v1" <2>
2528
ACCESS_TOKEN = "<access_token>" <3>
26-
NAMESPACE = "<namespace_name>" <4>
27-
REPO_NAME = "<repository_name>" <5>
28-
TAG = "<tag_name>" <6>
29+
ORG_NAME = "<organization_name>" <4>
2930

30-
def delete_image_tag():
31-
# Construct the full API URL for deleting the tag
32-
url = f"{API_BASE_URL}/repository/{NAMESPACE}/{REPO_NAME}/tag/{TAG}"
31+
def get_all_organization_applications():
32+
url = f"{API_BASE_URL}/organization/{ORG_NAME}/applications"
3333
headers = {
34-
"Authorization": f"Bearer {ACCESS_TOKEN}",
35-
"Content-Type": "application/json"
34+
"Authorization": f"Bearer {ACCESS_TOKEN}"
3635
}
3736

38-
# Send the DELETE request to the API
39-
response = requests.delete(url, headers=headers)
37+
response = requests.get(url, headers=headers)
4038

41-
# Check the response and print appropriate messages
4239
if response.status_code == 200:
43-
print("Tag deleted successfully")
40+
try:
41+
applications = response.json()
42+
# Print the raw response for debugging
43+
print("Raw response:", applications)
44+
45+
# Adjust parsing logic based on the response structure
46+
if isinstance(applications, dict) and 'applications' in applications:
47+
applications = applications['applications']
48+
49+
if isinstance(applications, list):
50+
print("Organization applications retrieved successfully:")
51+
for app in applications:
52+
# Updated key from 'title' to 'name'
53+
print(f"Name: {app['name']}, Client ID: {app['client_id']}")
54+
return applications
55+
else:
56+
print("Unexpected response format.")
57+
return []
58+
except requests.exceptions.JSONDecodeError:
59+
print("Error decoding JSON response:", response.text)
60+
return []
61+
else:
62+
print(f"Failed to retrieve applications. Status code: {response.status_code}, Response: {response.text}")
63+
return []
64+
65+
def delete_organization_application(client_id):
66+
url = f"{API_BASE_URL}/organization/{ORG_NAME}/applications/{client_id}"
67+
headers = {
68+
"Authorization": f"Bearer {ACCESS_TOKEN}"
69+
}
70+
71+
response = requests.delete(url, headers=headers)
72+
73+
if response.status_code == 204:
74+
print(f"Application {client_id} deleted successfully.")
4475
else:
45-
print("Failed to delete tag:", response.json())
76+
print(f"Failed to delete application {client_id}. Status code: {response.status_code}, Response: {response.text}")
77+
78+
def main():
79+
applications = get_all_organization_applications()
80+
for app in applications:
81+
if app['name'] != "<admin_token_app>": <5> # Skip the "admin-token-app"
82+
delete_organization_application(app['client_id'])
83+
else:
84+
print(f"Skipping deletion of application: {app['name']}")
4685

47-
# Execute the function
48-
delete_image_tag()
86+
# Execute the main function
87+
main()
4988
----
5089
<1> Includes the `import` library in your Python code.
5190
<2> The URL of your registry appended with `/api/v1`.
5291
<3> Your OAuth 2 access token.
53-
<4> The namespace that holds the image tag.
54-
<5> The repository that holds the image tag.
55-
<6> The tag name of the image.
92+
<4> The organization that holds the application.
93+
<5> The name of the application token to remain.
5694
57-
. Save the script as `prune_images.py`.
95+
. Save the script as `prune_applications.py`.
5896
5997
. Create a cron job that automatically runs the script:
6098
@@ -65,10 +103,10 @@ delete_image_tag()
65103
$ crontab -e
66104
----
67105
68-
.. In the editor, add the cron job for running the script. The following example runs the script every minute:
106+
.. In the editor, add the cron job for running the script. The following example runs the script once per month:
69107
+
70108
[source,text]
71109
----
72-
* * * * * sudo python /path/to/prune_images.py >> /var/log/prune_images.log 2>&1
110+
0 0 1 * * sudo python /path/to/prune_images.py >> /var/log/prune_images.log 2>&1
73111
----
74112

0 commit comments

Comments
 (0)