-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use akamai cli fast purge to refresh cache (#58)
- Loading branch information
1 parent
30d4a6f
commit 9f3f718
Showing
3 changed files
with
34 additions
and
127 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,8 @@ | ||
import yaml | ||
import json | ||
import sys | ||
import os | ||
import configparser | ||
import subprocess | ||
import requests | ||
from urllib.parse import urljoin | ||
from akamai.edgegrid import EdgeGridAuth, EdgeRc | ||
|
||
# Set up connectivity. Global var because it's a session that's used in multiple functions. | ||
s = requests.Session() | ||
|
@@ -14,123 +11,50 @@ | |
def getYMLFromUrl(url): | ||
return yaml.safe_load(s.get(url).content.decode('utf-8')) | ||
|
||
# Initializes the EdgeGrid auth using the .edgerc file (or some passed-in config). | ||
def initEdgeGridAuth(path="~/.edgerc"): | ||
# If the config file was passed in, use that. | ||
if len(sys.argv) > 1: | ||
path = sys.argv[1] | ||
config = configparser.RawConfigParser() | ||
config.read(os.path.expanduser(path)) | ||
|
||
# TODO: We might actually be able to authenticate without EdgeGridAuth, | ||
# which would reduce the number of dependencies. | ||
s.auth = EdgeGridAuth( | ||
client_token=config.get("default", "client_token"), | ||
client_secret=config.get("default", "client_secret"), | ||
access_token=config.get("default", "access_token") | ||
) | ||
|
||
def akamaiPost(url, body): | ||
return s.post(urljoin(base_url, url), json=body).content | ||
|
||
# Gets the hostname from the .edgerc file (or some passed-in config). | ||
def getHostFromConfig(path="~/.edgerc"): | ||
# If the config file was passed in, use that. | ||
if len(sys.argv) > 1: | ||
path = sys.argv[1] | ||
config = configparser.RawConfigParser() | ||
config.read(os.path.expanduser(path)) | ||
return config.get("default", "host") | ||
|
||
# Get the base url using the provided config | ||
base_url = "https://" + getHostFromConfig() | ||
|
||
#uses the paths for the app and the environments it's released on to generate | ||
#the XML used in the API request | ||
def createMetadata(paths, releases, appName): | ||
#Add the begining XML | ||
metadata = '<?xml version=\"1.0\"?>\n<!-- Submitted by bustCache.py script automatically -->\n<eccu>\n' | ||
|
||
#generate the paths XML | ||
for key in releases: | ||
# generate JS/CSS assets paths | ||
prefix = releases[key].get("content_path_prefix") | ||
if (prefix == None): | ||
prefix = '/' | ||
splitPrefix = f"apps{prefix}/{appName}".split('/') | ||
splitPrefix = list(filter(len, splitPrefix)) | ||
splitPrefixLength = len(splitPrefix) | ||
closingTag = '' | ||
for i in range(0, splitPrefixLength): | ||
metadata += ' ' * i + f'<match:recursive-dirs value=\"{splitPrefix[i]}\">\n' | ||
closingTag += ' ' * (splitPrefixLength - i - 1) +'</match:recursive-dirs>\n' | ||
metadata += ' ' * (i + 1) + '<revalidate>now</revalidate>\n' | ||
metadata += closingTag | ||
# generate HTML paths | ||
for path in paths: | ||
path = prefix + path | ||
splitPath = path.split('/') | ||
splitPath = list(filter(len, splitPath)) | ||
metadataClosingTags = '' | ||
pathLength = len(splitPath) | ||
#create opening and closing tags | ||
|
||
for i in range(0, pathLength): | ||
metadata += ' ' * i + f'<match:recursive-dirs value=\"{splitPath[i]}\">\n' | ||
metadataClosingTags += ' ' * (pathLength - i - 1) + '</match:recursive-dirs>\n' | ||
metadata += ' ' * pathLength + '<revalidate>now</revalidate>\n' | ||
metadata += metadataClosingTags | ||
# generate chrome JSON config paths | ||
prefix = releases[key].get("content_path_prefix") | ||
if (prefix == None): | ||
prefix = '' | ||
chromeConfigPath = f'{prefix}/config/chrome'.split('/') | ||
chromeSplitPath = list(filter(len, chromeConfigPath)) | ||
chromeSplitPathLen = len(chromeSplitPath) | ||
metadataClosingTags = '' | ||
for i in range(0, chromeSplitPathLen): | ||
metadata += ' ' * i + f'<match:recursive-dirs value=\"{chromeSplitPath[i]}\">\n' | ||
metadataClosingTags += ' ' * (chromeSplitPathLen - i - 1) +'</match:recursive-dirs>\n' | ||
metadata += ' ' * (i + 1) + '<revalidate>now</revalidate>\n' | ||
metadata += metadataClosingTags | ||
metadata += '</eccu>' | ||
|
||
return metadata | ||
|
||
def createRequest(paths, releases, appName): | ||
body = { | ||
"propertyName": "cloud.redhat.com", | ||
"propertyNameExactMatch": 'true', | ||
"propertyType": "HOST_HEADER", | ||
"metadata": createMetadata(paths, releases, appName), | ||
"notes": "purging cache for new deployment", | ||
"requestName": f"Invalidate cache for {appName}", | ||
"statusUpdateEmails": [ | ||
"[email protected]", | ||
"[email protected]" | ||
] | ||
} | ||
|
||
return body | ||
|
||
#main | ||
def main(): | ||
print(f'Cache purge started with: {sys.argv}') | ||
edgeRcPath = sys.argv[1] | ||
appName = sys.argv[2] | ||
|
||
#connect to akamai and validate | ||
initEdgeGridAuth() | ||
|
||
branch = sys.argv[3] | ||
domain = 'https://console.stage.redhat.com' | ||
if 'prod' in branch: | ||
domain = 'https://console.redhat.com' | ||
entryBase = f'/apps/{appName}' | ||
fedModsBase = f'{entryBase}/fed-mods.json' | ||
#get the data to use for cache busting | ||
paths = [] | ||
try: | ||
paths = getYMLFromUrl("https://console.redhat.com/config/main.yml").get(appName).get("frontend").get("paths") | ||
except: | ||
print("WARNING: this app has no path, if that's okay ignore this :)") | ||
paths = [] | ||
|
||
releases = getYMLFromUrl("https://console.redhat.com/config/releases.yml") | ||
|
||
akamaiPost("/eccu-api/v1/requests", createRequest(paths, releases, appName)) | ||
print(paths) | ||
purgeSuffixes = [] | ||
purgeUrls = [] | ||
for key in releases: | ||
prefix = releases[key].get("content_path_prefix") | ||
if (prefix == None): | ||
prefix = '' | ||
purgeSuffixes.append(f'{prefix}{fedModsBase}') | ||
for path in paths: | ||
purgeSuffixes.append(f'{prefix}{path}') | ||
|
||
for suffix in purgeSuffixes: | ||
purgeUrls.append(f'{domain}{suffix}') | ||
|
||
for endpoint in purgeUrls: | ||
print(f'Purging endpoint cache: {endpoint}') | ||
try: | ||
subprocess.check_output(['akamai', 'purge', '--edgerc', edgeRcPath , 'invalidate', endpoint]) | ||
except subprocess.CalledProcessError as e: | ||
print(e.output) | ||
sys.exit(1) | ||
|
||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,3 @@ | ||
asn1crypto==0.24.0 | ||
certifi==2019.3.9 | ||
cffi==1.12.3 | ||
chardet==3.0.4 | ||
cryptography==3.2 | ||
edgegrid-python==1.1.1 | ||
enum34==1.1.6 | ||
httpie==1.0.3 | ||
httpie-edgegrid==1.0.2 | ||
idna==2.8 | ||
ipaddress==1.0.22 | ||
ndg-httpsclient==0.5.1 | ||
pyasn1==0.4.5 | ||
pycparser==2.19 | ||
Pygments==2.4.0 | ||
pyOpenSSL==19.0.0 | ||
PyYAML==5.1 | ||
requests==2.21.0 | ||
six==1.12.0 | ||
urllib3==1.24.2 |