Octopus.Script exported 2019-02-11 by ajwightm belongs to ‘Akamai’ category.
Allows to purge CP codes using the Content Control Utility (CCU) v3 REST API.
Parameters
When steps based on the template are included in a project’s deployment process, the parameters below can be set.
Client Token
AkamaiClientToken =
Authentication token used in client authentication. Available in Luna Portal.
Client Access Token
AkamaiClientAccessToken =
Authentication token used in client authentication. Available in Luna Portal.
Secret
AkamaiSecret =
Authentication password used in client authentication. Available in Luna Portal.
CPCode
AkamaiCPCode =
The CPCode for which to execute the purge operation
Host
AkamaiHost =
Akamai Host (no HTTP/HTTPS). Available in Luna Portal.
Action
AkamaiAction = invalidate
The action to execute on the purge operation
Domain
AkamaiDomain = production
The Akamai domain to perform the purge operation on
Script body
Steps based on this template will execute the following PowerShell script.
$clientToken = $OctopusParameters['AkamaiClientToken']
$clientAccessToken = $OctopusParameters['AkamaiClientAccessToken']
$clientSecret = $OctopusParameters['AkamaiSecret']
$cpcode = $OctopusParameters['AkamaiCPCode']
$akhost = $OctopusParameters['AkamaiHost']
$action = $OctopusParameters['AkamaiAction']
$domain = $OctopusParameters['AkamaiDomain']
# NOTICE : PowerShell EdgeGrid Client has been deprecated and will reach End of Life soon. For more information, please see https://developer.akamai.com/blog/2018/11/13/akamai-powershell-edgegrid-client-end-life-notice
# Copied from https://github.com/akamai-open/AkamaiOPEN-powershell/blob/master/Invoke-AkamaiOPEN.ps1
function Invoke-AkamaiOpenRequest {
param(
[Parameter(Mandatory=$true)]
[ValidateSet("GET", "PUT", "POST", "DELETE")]
[string]$Method,
[Parameter(Mandatory=$true)][string]$ClientToken,
[Parameter(Mandatory=$true)][string]$ClientAccessToken,
[Parameter(Mandatory=$true)][string]$ClientSecret,
[Parameter(Mandatory=$true)][string]$ReqURL,
[Parameter(Mandatory=$false)][string]$Body,
[Parameter(Mandatory=$false)][string]$MaxBody = 131072
)
#Function to generate HMAC SHA256 Base64
Function Crypto ($secret, $message)
{
[byte[]] $keyByte = [System.Text.Encoding]::ASCII.GetBytes($secret)
[byte[]] $messageBytes = [System.Text.Encoding]::ASCII.GetBytes($message)
$hmac = new-object System.Security.Cryptography.HMACSHA256((,$keyByte))
[byte[]] $hashmessage = $hmac.ComputeHash($messageBytes)
$Crypt = [System.Convert]::ToBase64String($hashmessage)
return $Crypt
}
#ReqURL Verification
If (($ReqURL -as [System.URI]).AbsoluteURI -eq $null -or $ReqURL -notmatch "akamaiapis.net")
{
throw "Error: Ivalid Request URI"
}
#Sanitize Method param
$Method = $Method.ToUpper()
#Split $ReqURL for inclusion in SignatureData
$ReqArray = $ReqURL -split "(.*\/{2})(.*?)(\/)(.*)"
#Timestamp for request signing
$TimeStamp = [DateTime]::UtcNow.ToString("yyyyMMddTHH:mm:sszz00")
#GUID for request signing
$Nonce = [GUID]::NewGuid()
#Build data string for signature generation
$SignatureData = $Method + "`thttps`t"
$SignatureData += $ReqArray[2] + "`t" + $ReqArray[3] + $ReqArray[4]
#Add body to signature. Truncate if body is greater than max-body (Akamai default is 131072). PUT Medthod does not require adding to signature.
if ($Body -and $Method -eq "POST")
{
$Body_SHA256 = [System.Security.Cryptography.SHA256]::Create()
if($Body.Length -gt $MaxBody){
$Post_Hash = [System.Convert]::ToBase64String($Body_SHA256.ComputeHash([System.Text.Encoding]::ASCII.GetBytes($Body.Substring(0,$MaxBody))))
}
else{
$Post_Hash = [System.Convert]::ToBase64String($Body_SHA256.ComputeHash([System.Text.Encoding]::ASCII.GetBytes($Body)))
}
$SignatureData += "`t`t" + $Post_Hash + "`t"
}
else
{
$SignatureData += "`t`t`t"
}
$SignatureData += "EG1-HMAC-SHA256 "
$SignatureData += "client_token=" + $ClientToken + ";"
$SignatureData += "access_token=" + $ClientAccessToken + ";"
$SignatureData += "timestamp=" + $TimeStamp + ";"
$SignatureData += "nonce=" + $Nonce + ";"
#Generate SigningKey
$SigningKey = Crypto -secret $ClientSecret -message $TimeStamp
#Generate Auth Signature
$Signature = Crypto -secret $SigningKey -message $SignatureData
#Create AuthHeader
$AuthorizationHeader = "EG1-HMAC-SHA256 "
$AuthorizationHeader += "client_token=" + $ClientToken + ";"
$AuthorizationHeader += "access_token=" + $ClientAccessToken + ";"
$AuthorizationHeader += "timestamp=" + $TimeStamp + ";"
$AuthorizationHeader += "nonce=" + $Nonce + ";"
$AuthorizationHeader += "signature=" + $Signature
#Create IDictionary to hold request headers
$Headers = @{}
#Add Auth header
$Headers.Add('Authorization',$AuthorizationHeader)
#Add additional headers if POSTing or PUTing
If ($Body)
{
# turn off the "Expect: 100 Continue" header
# as it's not supported on the Akamai side.
[System.Net.ServicePointManager]::Expect100Continue = $false
}
#Check for valid Methods and required switches
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
if ($Method -eq "PUT" -or $Method -eq "POST") {
if ($Body) {
try{
Invoke-RestMethod -Method $Method -Uri $ReqURL -Headers $Headers -Body $Body -ContentType 'application/json'
}
catch{
Write-Host $_ -fore green
}
}
else {
Invoke-RestMethod -Method $Method -Uri $ReqURL -Headers $Headers -ContentType 'application/json'
}
}
else {
#Invoke API call with GET or DELETE and return
Invoke-RestMethod -Method $Method -Uri $ReqURL -Headers $Headers
}
}
function Perform-AkamaiRequest {
param (
[string]$request,
[string]$method="Get",
[int]$expectedStatusCode=200,
$body)
$baseUrl = "https://" + $akhost
$uri = "{0}{1}" -f $baseUrl,$request
$json = ConvertTo-Json $body -Compress
$response = Invoke-AkamaiOpenRequest -Method $method -ClientToken $clientToken -ClientAccessToken $clientAccessToken -ClientSecret $clientSecret -ReqURL $uri -Body $json
if ($response.httpStatus -ne $expectedStatusCode){
Write-Error "Request not processed correctly: $($response.detail)"
} elseif ($response.detail) {
Write-Verbose $response.detail
}
$response
}
function Request-Purge {
param ([Int]$cpcode,[string]$action="remove",[string]$domain="production")
$body = @{
objects = @($cpcode)
}
Perform-AkamaiRequest "/ccu/v3/$action/cpcode/$domain" "Post" 201 $body
}
$purge = Request-Purge $cpcode $action $domain
Write-Output "Purge request created"
Write-Output "PurgeId: $($purge.purgeId)"
Write-Output "SupportId: $($purge.supportId)"
Provided under the Apache License version 2.0.
To use this template in Octopus Deploy, copy the JSON below and paste it into the Library → Step templates → Import dialog.
{
"Id": "ee4a6957-7d98-4dcf-8f94-78f19ab1c6e0",
"Name": "Akamai - CPCode Fast Purge",
"Description": "Allows to purge CP codes using the Content Control Utility (CCU) v3 REST API.",
"Version": 2,
"ExportedAt": "2019-02-11T18:51:20.358Z",
"ActionType": "Octopus.Script",
"Author": "ajwightm",
"Parameters": [
{
"Id": "293e2cc1-e471-4801-8a9c-42633a3c9122",
"Name": "AkamaiClientToken",
"Label": "Client Token",
"HelpText": "Authentication token used in client authentication. Available in Luna Portal.",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
},
"Links": {}
},
{
"Id": "e0edcbea-bfdd-4781-9a8a-55b08eba6ed5",
"Name": "AkamaiClientAccessToken",
"Label": "Client Access Token",
"HelpText": "Authentication token used in client authentication. Available in Luna Portal.",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
},
"Links": {}
},
{
"Id": "c1ea0502-f68e-4890-99a2-3c721d16b7f0",
"Name": "AkamaiSecret",
"Label": "Secret",
"HelpText": "Authentication password used in client authentication. Available in Luna Portal.",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "Sensitive"
},
"Links": {}
},
{
"Id": "f54e1b4a-3960-483b-88c9-5ea7a94698a0",
"Name": "AkamaiCPCode",
"Label": "CPCode",
"HelpText": "The CPCode for which to execute the purge operation",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
},
"Links": {}
},
{
"Id": "a334eabb-8a36-4c24-b728-52f834f8a893",
"Name": "AkamaiHost",
"Label": "Host",
"HelpText": "Akamai Host (no HTTP/HTTPS). Available in Luna Portal.",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
},
"Links": {}
},
{
"Id": "8482001d-a6fc-4e72-b9be-8cc584a39b36",
"Name": "AkamaiAction",
"Label": "Action",
"HelpText": "The action to execute on the purge operation",
"DefaultValue": "invalidate",
"DisplaySettings": {
"Octopus.ControlType": "Select",
"Octopus.SelectOptions": "invalidate\nremove"
},
"Links": {}
},
{
"Id": "e1c3dfa0-7118-4e23-9315-c03ea3662125",
"Name": "AkamaiDomain",
"Label": "Domain",
"HelpText": "The Akamai domain to perform the purge operation on",
"DefaultValue": "production",
"DisplaySettings": {
"Octopus.ControlType": "Select",
"Octopus.SelectOptions": "production\nstaging"
},
"Links": {}
}
],
"Properties": {
"Octopus.Action.Script.Syntax": "PowerShell",
"Octopus.Action.Script.ScriptSource": "Inline",
"Octopus.Action.Script.ScriptBody": "$clientToken = $OctopusParameters['AkamaiClientToken']\n$clientAccessToken = $OctopusParameters['AkamaiClientAccessToken']\n$clientSecret = $OctopusParameters['AkamaiSecret']\n$cpcode = $OctopusParameters['AkamaiCPCode']\n$akhost = $OctopusParameters['AkamaiHost']\n$action = $OctopusParameters['AkamaiAction']\n$domain = $OctopusParameters['AkamaiDomain']\n\n# NOTICE : PowerShell EdgeGrid Client has been deprecated and will reach End of Life soon. For more information, please see https://developer.akamai.com/blog/2018/11/13/akamai-powershell-edgegrid-client-end-life-notice\n# Copied from https://github.com/akamai-open/AkamaiOPEN-powershell/blob/master/Invoke-AkamaiOPEN.ps1\nfunction Invoke-AkamaiOpenRequest {\n\tparam(\n\t\t[Parameter(Mandatory=$true)]\n\t\t[ValidateSet(\"GET\", \"PUT\", \"POST\", \"DELETE\")]\n\t\t[string]$Method,\n\t\t[Parameter(Mandatory=$true)][string]$ClientToken,\n\t\t[Parameter(Mandatory=$true)][string]$ClientAccessToken,\n\t\t[Parameter(Mandatory=$true)][string]$ClientSecret,\n\t\t[Parameter(Mandatory=$true)][string]$ReqURL,\n\t\t[Parameter(Mandatory=$false)][string]$Body,\n\t\t[Parameter(Mandatory=$false)][string]$MaxBody = 131072\n\t\t)\n\n\t#Function to generate HMAC SHA256 Base64\n\tFunction Crypto ($secret, $message)\n\t{\n\t\t[byte[]] $keyByte = [System.Text.Encoding]::ASCII.GetBytes($secret)\n\t\t[byte[]] $messageBytes = [System.Text.Encoding]::ASCII.GetBytes($message)\n\t\t$hmac = new-object System.Security.Cryptography.HMACSHA256((,$keyByte))\n\t\t[byte[]] $hashmessage = $hmac.ComputeHash($messageBytes)\n\t\t$Crypt = [System.Convert]::ToBase64String($hashmessage)\n\n\t\treturn $Crypt\n\t}\n\n\t#ReqURL Verification\n\tIf (($ReqURL -as [System.URI]).AbsoluteURI -eq $null -or $ReqURL -notmatch \"akamaiapis.net\")\n\t{\n\t\tthrow \"Error: Ivalid Request URI\"\n\t}\n\n\t#Sanitize Method param\n\t$Method = $Method.ToUpper()\n\n\t#Split $ReqURL for inclusion in SignatureData\n\t$ReqArray = $ReqURL -split \"(.*\\/{2})(.*?)(\\/)(.*)\"\n\n\t#Timestamp for request signing\n\t$TimeStamp = [DateTime]::UtcNow.ToString(\"yyyyMMddTHH:mm:sszz00\")\n\n\t#GUID for request signing\n\t$Nonce = [GUID]::NewGuid()\n\n\t#Build data string for signature generation\n\t$SignatureData = $Method + \"`thttps`t\"\n\t$SignatureData += $ReqArray[2] + \"`t\" + $ReqArray[3] + $ReqArray[4]\n\n\t#Add body to signature. Truncate if body is greater than max-body (Akamai default is 131072). PUT Medthod does not require adding to signature.\n\t\n\tif ($Body -and $Method -eq \"POST\")\n\t{\n\t $Body_SHA256 = [System.Security.Cryptography.SHA256]::Create()\n\t if($Body.Length -gt $MaxBody){\n\t\t$Post_Hash = [System.Convert]::ToBase64String($Body_SHA256.ComputeHash([System.Text.Encoding]::ASCII.GetBytes($Body.Substring(0,$MaxBody))))\n\t }\n\t else{\n\t\t$Post_Hash = [System.Convert]::ToBase64String($Body_SHA256.ComputeHash([System.Text.Encoding]::ASCII.GetBytes($Body)))\n\t }\n\n\t $SignatureData += \"`t`t\" + $Post_Hash + \"`t\"\n\t}\n\telse\n\t{\n\t $SignatureData += \"`t`t`t\"\n\t}\n\n\t$SignatureData += \"EG1-HMAC-SHA256 \"\n\t$SignatureData += \"client_token=\" + $ClientToken + \";\"\n\t$SignatureData += \"access_token=\" + $ClientAccessToken + \";\"\n\t$SignatureData += \"timestamp=\" + $TimeStamp + \";\"\n\t$SignatureData += \"nonce=\" + $Nonce + \";\"\n\n\t#Generate SigningKey\n\t$SigningKey = Crypto -secret $ClientSecret -message $TimeStamp\n\n\t#Generate Auth Signature\n\t$Signature = Crypto -secret $SigningKey -message $SignatureData\n\n\t#Create AuthHeader\n\t$AuthorizationHeader = \"EG1-HMAC-SHA256 \"\n\t$AuthorizationHeader += \"client_token=\" + $ClientToken + \";\"\n\t$AuthorizationHeader += \"access_token=\" + $ClientAccessToken + \";\"\n\t$AuthorizationHeader += \"timestamp=\" + $TimeStamp + \";\"\n\t$AuthorizationHeader += \"nonce=\" + $Nonce + \";\"\n\t$AuthorizationHeader += \"signature=\" + $Signature\n\n\t#Create IDictionary to hold request headers\n\t$Headers = @{}\n\n\t#Add Auth header\n\t$Headers.Add('Authorization',$AuthorizationHeader)\n\n\t#Add additional headers if POSTing or PUTing\n\tIf ($Body)\n\t{\n\t # turn off the \"Expect: 100 Continue\" header\n\t # as it's not supported on the Akamai side.\n\t [System.Net.ServicePointManager]::Expect100Continue = $false\n\t}\n\t\n\t#Check for valid Methods and required switches\n\t[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12\n\tif ($Method -eq \"PUT\" -or $Method -eq \"POST\") {\n\t\tif ($Body) {\n\t\t\ttry{\n\t\t\t\tInvoke-RestMethod -Method $Method -Uri $ReqURL -Headers $Headers -Body $Body -ContentType 'application/json'\n\t\t\t}\n\t\t\tcatch{\n\t\t\t\tWrite-Host $_ -fore green\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t Invoke-RestMethod -Method $Method -Uri $ReqURL -Headers $Headers -ContentType 'application/json'\n\t\t}\n\t}\n\telse {\n\t\t#Invoke API call with GET or DELETE and return\n\t\tInvoke-RestMethod -Method $Method -Uri $ReqURL -Headers $Headers\n\t}\n}\n\nfunction Perform-AkamaiRequest {\n param (\n [string]$request, \n [string]$method=\"Get\", \n [int]$expectedStatusCode=200, \n $body)\n\n $baseUrl = \"https://\" + $akhost\n $uri = \"{0}{1}\" -f $baseUrl,$request\n\n $json = ConvertTo-Json $body -Compress\n $response = Invoke-AkamaiOpenRequest -Method $method -ClientToken $clientToken -ClientAccessToken $clientAccessToken -ClientSecret $clientSecret -ReqURL $uri -Body $json\n\t\n if ($response.httpStatus -ne $expectedStatusCode){\n Write-Error \"Request not processed correctly: $($response.detail)\"\n } elseif ($response.detail) {\n Write-Verbose $response.detail\n }\n\n $response\n}\n\nfunction Request-Purge {\n param ([Int]$cpcode,[string]$action=\"remove\",[string]$domain=\"production\")\n\n $body = @{\n objects = @($cpcode)\n }\n\n Perform-AkamaiRequest \"/ccu/v3/$action/cpcode/$domain\" \"Post\" 201 $body\n}\n\n$purge = Request-Purge $cpcode $action $domain\n\nWrite-Output \"Purge request created\"\nWrite-Output \"PurgeId: $($purge.purgeId)\"\nWrite-Output \"SupportId: $($purge.supportId)\" ",
"Octopus.Action.RunOnServer": "false",
"Octopus.Action.Script.ScriptFileName": null,
"Octopus.Action.Package.FeedId": null,
"Octopus.Action.Package.PackageId": null
},
"Category": "Akamai",
"HistoryUrl": "https://github.com/OctopusDeploy/Library/commits/master/step-templates//opt/buildagent/work/75443764cd38076d/step-templates/akamai-cpcode-fastpurge.json",
"Website": "/step-templates/ee4a6957-7d98-4dcf-8f94-78f19ab1c6e0",
"Logo": "iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAABhQTFRFseDvTrjc1+/3f8zlKqrU////AJnM7/n8E0I9ngAABR5JREFUeNrsndly6zAIQAFJ1v//8c16GydGK3IgA9O3tqOcsCNZhvQjAg7iIA7iIA7iIA7iIA7iIA7iIA7iIA7iIA7iIA5yIAQUnkI2QS4AGLedmAPJEN4QbhJsgdAhxFKMBSAcBYIpZ4djigjZUtTKYTtWBqX1IgeS8Rgj5JQMgdB3MaRAOKM6DUMIhPON8zBEQNhIxWdLoOePHhDWOY7zPX78ecQQ4PsgjFXF/Fk74rHmHv8wCzP377lRHVy6F0z+UyDAfCJ4M6gWitncCfIc+2BF2I4xo5YJkBazAty6JcKpIJx7vJaHNIAxijIKkmPVPfIgxpivgCwHVQNzq4RTQOocFLdJibQepM4RNgEJq0GqHDPeMVp1wgKOebPiKx1BkCoHbHLS7igglQdhBcc+DsqC1PJ5Iwdeq/c/QWQrGVoDwjWD7RyXgp37bHA0n2z0k04QKDtlhmpJeIHgP9n1N5fma4SkD4Qq6geZwjbvmzCUB6kUWFC0qL5RxGvdDNIgFQcB2S6DQo/Dg4Bh5fKvx5ul/y6HsiBlw8orWvHn5C9IglQMKzY18KMNXJYDyWXDWjc0hSaVQK+SmZQO7T0rwS2R7374JPlUSpYC4VJhybDwaEzHhwRee5eEH6RAyrViaPGO+oArchvYhCgEUp5hUUO11zgZGt2lAxGFYLUn6pg2bkPnCmBOIWwq3LsHdPaMA7EO1igEB2e/43vybSBUDFlU5DjAuMdc2WkjrFAIHk5Nbzs674P663kVkX3UJhAuqTMKwc+yBsv7OPTRTXWP6JpAykk9MDnyWSe1bkbRJwwIg5QHQGzcvQ2OkHos5H1/LoiCUDH2Aj83xZGMsE+cKAkSijshKFq1fwQ6lAPhRouH1YnQmayXYIdiIGXLCoyjz8pf2xCkxkGhI4mIHmh6TuuCEEjRsvLSw35BchxULk9gjWG9GZjIOAiK2RClI9Zhn9swNa2vXa6z4kjM7w/GKAASS3VWXubpb64C0yC5Oa1jWia52rLXQaBYY4fPAdeXBBojYD2LYNINgsXKF0/wkLUgH5Hgywqpg5QHjGoUUgUpB620MKkLg1ROyZ3zSMVCkPCuEdIOUp47kBrLmgQBNZYlBULpR0wrqQfBJo2gdZCkxkWEQEA9SG4Dyb+ikfQjIGgApBx+H5yYfwQk2NdI+BUQMANS3mB/1ChgAIQqx2PNgKTK8Xs0DrLtfMgESHkcdPchMgwCrxozoZFQAUErINTwdIIJkMqo8TbByyZAinuhd9tKJkBqTgJWQKB2xC1GGyC54iQpkw2QVH+a1QhIEDo++XUQqtmWFRAbtjVx8CyYAzFhWwKHMw2BVBp3OyCVp5LsgFhwd4lD/oZAqg2vGZCsXiUyjyYZAlHvJbOP7wVzINpzSbuRK88lHd6qu+LqefhHtb/3xE/V/t4DkjfFxtWV0TQbV19qVhy5OmuMqLZS6fwIetNi73dJ0zd6KQFR27/3W3fQSTLgpjpbk5HlVZIMra6RZGxxhSSDazdcLWsDRJ9OhlfWVtOPf4XKMuOELYCqamXGqKn3Cn+tIM3XxqsH4S/yJ2sg7N2+wRoIezfd2UpZ99qOM9+ikta+SOXUPC+0Vti+HYmlVmJf/QTGQK4o8ZsooqswNxjGM9xe+Oti31cHxkB4lhjIGEjKLAvYArnTHF6PB/ZAbpqB93dt2gR50Ly8/ZSSXRBzmd1BHMRBHMRBHMRBHMRBHMRBHMRBHMRBHMRBHORM+SfAAMOMGvrIfh0UAAAAAElFTkSuQmCC",
"$Meta": {
"Type": "ActionTemplate"
}
}
Page updated on Monday, February 11, 2019