Skip to content

Commit

Permalink
Use akamai cli fast purge to refresh cache (#58)
Browse files Browse the repository at this point in the history
  • Loading branch information
Hyperkid123 committed Nov 10, 2021
1 parent 30d4a6f commit c720cb9
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 127 deletions.
2 changes: 1 addition & 1 deletion src/Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ node {
withCredentials([file(credentialsId: "jenkins-eccu-cache-purge", variable: 'EDGERC')]) {
//path to .edgerc file is now set to $EDGERC"
//Bust the current cache
sh "python3 bustCache.py $EDGERC ${APP_NAME}"
sh "python3 bustCache.py $EDGERC ${APP_NAME} ${BRANCH}"
}
}
}
Expand Down
142 changes: 33 additions & 109 deletions src/akamai_cache_buster/bustCache.py
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()
Expand All @@ -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():
edgeRcPath = sys.argv[1]
appName = sys.argv[2]

#connect to akamai and validate
initEdgeGridAuth()

branch = sys.argv[3]
print(f'Cache purge started with: {edgeRcPath} {appName} {branch}')
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()
17 changes: 0 additions & 17 deletions src/akamai_cache_buster/requirements.txt
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

0 comments on commit c720cb9

Please sign in to comment.