- if an emergency release is needed, it will automatically point to the new infrastructure and it could not be ready for the switch over.
- if an unexpected problem is found after the release and we want to rollback, we would need to modify all the Octopus variables and create a new release to rollback to the old infrastructure (or rollback to the old version of the code).
- additionally, in both cases, creating a new release after the deployment could pick up variable changes made for future releases like feature flags.
To address those possible problems, I decided to add a rollback role to all the servers that were planned to be deployed (30+) and then add the same rollback role to the existing connection string variables, and then create new variables with the same roles as the originals. This way if a new release needs to be created it will use the rollback variables. Then right before the release we would remove the rollback role so when deploying the new connection strings would be used. And in the case of needing a rollback we would just add back the rollback role and deploy the same release.
The only problem was adding and removing that role to the large amount of servers, this is were I just put together my very first python program to use Octopus Api to add or remove a role. The code is a bit too raw, but other members of the team have already started to used it to setup new deployment targets. I have to say that I'm impressed how natural and quick was to write the script in Python.
import requests
OctopusUrl = 'http://***octopusserver***'
headers = {'X-Octopus-ApiKey' : 'API-***********'}
newRole = 'Rollback'
environmentName = 'Production'
#environment
machinesUrl = 'null'
environments = requests.get(OctopusUrl+'/api/environments', headers=headers).json()
for environment in environments['Items']:
if (environment['Name'] == environmentName):
machinesUrl = environment['Links']['Machines']
#machines
machines = requests.get(OctopusUrl+machinesUrl, headers=headers).json()
machinesList = []
machineEndPage = False
while not machineEndPage:
for machine in machines['Items']:
if ('MainRole in machine["Roles"]):
machinesList.append(machine)
nextMachinesUrl =machines['Links'].get('Page.Next', 'null')
if (nextMachinesUrl != 'null') :
machines = requests.get(OctopusUrl+nextMachinesUrl, headers=headers).json()
else:
machineEndPage = True
for machine in machinesList:
#if (newRole not in machine['Roles']): #Add role
#machine['Roles'].append(newRole)
if (newRole in machine['Roles']): # remove
machine['Roles'].remove(newRole)
machineUrl = OctopusUrl+machine['Links']['Self']
result = requests.put(machineUrl, json=machine, headers=headers)
print(machine['Name']+' '+result)