Skip to content
This repository has been archived by the owner on Dec 4, 2024. It is now read-only.

Commit

Permalink
Refactor process_json and get_app_info in bluegreen_deploy.py (#174)
Browse files Browse the repository at this point in the history
* create list_marathon_apps function

* refactor

* Separate app validation logic into function

* refactor

* refactor get_service_port

* refactor set_service_port

* create set_app_id function

* factor out `get_app_info` method

* Pep8 fixes

* Immediatly catch stuck deploy

* Pep8 fixes
  • Loading branch information
JamesAwesome authored and brndnmtthws committed Apr 28, 2016
1 parent 173245a commit c427f5c
Showing 1 changed file with 136 additions and 78 deletions.
214 changes: 136 additions & 78 deletions bluegreen_deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,44 +53,21 @@ def query_yes_no(question, default="yes"):
"(or 'y' or 'n').\n")


def get_app_info(args, deployment_group, alt_port):
url = args.marathon + "/v2/apps"
def marathon_get_request(args, path):
url = args.marathon + path
response = requests.get(url, auth=get_marathon_auth_params(args))
response.raise_for_status()
apps = response.json()
existing_app = None
colour = 'blue'
next_port = alt_port
resuming = False
for app in apps['apps']:
if 'labels' in app and \
'HAPROXY_DEPLOYMENT_GROUP' in app['labels'] and \
'HAPROXY_DEPLOYMENT_COLOUR' in app['labels'] and \
app['labels']['HAPROXY_DEPLOYMENT_GROUP'] == deployment_group:
if existing_app is not None:
if args.resume:
logger.info("Found previous deployment, resuming")
resuming = True
if existing_app['labels']['HAPROXY_DEPLOYMENT_STARTED_AT']\
< app['labels']['HAPROXY_DEPLOYMENT_STARTED_AT']:
# stop here
break
else:
raise Exception("There appears to be an existing"
" deployment in progress")

prev_colour = app['labels']['HAPROXY_DEPLOYMENT_COLOUR']
prev_port = app['ports'][0]
existing_app = app
if prev_port == int(alt_port):
next_port = app['labels']['HAPROXY_0_PORT']
else:
next_port = alt_port
if prev_colour == 'blue':
colour = 'green'
else:
colour = 'blue'
return (colour, next_port, existing_app, resuming)
return response


def list_marathon_apps(args):
response = marathon_get_request(args, "/v2/apps")
return response.json()['apps']


def fetch_marathon_app(args, app_ip):
response = marathon_get_request(args, "/v2/apps" + app_id)
return response.json()['app']


def get_hostports_from_backends(hmap, backends, haproxy_instance_count):
Expand Down Expand Up @@ -311,34 +288,24 @@ def start_deployment(args, app, existing_app, resuming):


def get_service_port(app):
if 'container' in app and \
'docker' in app['container'] and \
'portMappings' in app['container']['docker']:
portMappings = app['container']['docker']['portMappings']
# Just take the first servicePort
return portMappings[0]['servicePort']
return app['ports'][0]


def set_service_port(app, port):
if 'container' in app and \
'docker' in app['container'] and \
'portMappings' in app['container']['docker']:
app['container']['docker']['portMappings'][0]['servicePort'] = \
int(port)
return app
app['ports'][0] = int(servicePort)
return app
try:
return app['container']['docker']['portMappings'][0]['servicePort']
except KeyError:
return app['ports'][0]


def process_json(args, out=sys.stdout):
with open(args.json, 'r') as content_file:
content = content_file.read()
def set_service_port(app, servicePort):
try:
app['container']['docker']['portMappings'][0]['servicePort'] \
= int(servicePort)
except KeyError:
app['ports'][0] = int(servicePort)

return app

app = json.loads(content)

app_id = app['id']
if app_id is None:
def validate_app(app):
if app['id'] is None:
raise Exception("App doesn't contain a valid App ID")

if 'labels' not in app:
Expand All @@ -354,30 +321,113 @@ def process_json(args, out=sys.stdout):
"HAPROXY_DEPLOYMENT_ALT_PORT label"
)

deployment_group = app['labels']['HAPROXY_DEPLOYMENT_GROUP']
alt_port = app['labels']['HAPROXY_DEPLOYMENT_ALT_PORT']
app['labels']['HAPROXY_APP_ID'] = app_id

service_port = get_service_port(app)

(colour, port, existing_app, resuming) = \
get_app_info(args, deployment_group, alt_port)
def set_app_ids(app, colour):
app['labels']['HAPROXY_APP_ID'] = app['id']
app['id'] = app['id'] + '-' + colour

app = set_service_port(app, port)

app['id'] = app_id + "-" + colour
if app['id'][0] != '/':
app['id'] = '/' + app['id']
if existing_app is not None:

return app


def set_service_ports(app, servicePort):
app['labels']['HAPROXY_0_PORT'] = str(get_service_port(app))
try:
app['container']['docker']['portMappings'][0]['servicePort'] \
= int(servicePort)
return app
except KeyError:
app['ports'][0] = int(servicePort)
return app


def select_next_port(app):
if int(app['ports'][0]) \
== int(app['labels']['HAPROXY_DEPLOYMENT_ALT_PORT']):

return int(app['labels']['HAPROXY_0_PORT'])
else:
return int(app['labels']['HAPROXY_DEPLOYMENT_ALT_PORT'])


def select_next_colour(app):
if app['labels'].get('HAPROXY_DEPLOYMENT_COLOUR') == 'blue':
return 'green'
else:
return 'blue'


def sort_deploys(apps):
return sorted(apps, key=lambda a: a.get('labels', {})
.get('HAPROXY_DEPLOYMENT_STARTED_AT', '0'))


def select_last_deploy(apps):
return sort_deploys(apps).pop()


def select_last_two_deploys(apps):
return sort_deploys(apps)[0:2]


def get_deployment_group(app):
return app.get('labels', {}).get('HAPROXY_DEPLOYMENT_GROUP')


def select_previous_deploys(apps, deployment_group):
return [a for a in apps if get_deployment_group(a) == deployment_group]


def prepare_deploy(args, previous_deploys, app):
""" Return a blue or a green version of `app` based on prexisting deploys
"""
if len(previous_deploys) > 0:
last_deploy = select_last_deploy(previous_deploys)

app['instances'] = args.initial_instances
app['labels']['HAPROXY_DEPLOYMENT_TARGET_INSTANCES'] = \
str(existing_app['instances'])
next_colour = select_next_colour(last_deploy)
next_port = select_next_port(last_deploy)
deployment_target_instances = last_deploy['instances']
else:
app['labels']['HAPROXY_DEPLOYMENT_TARGET_INSTANCES'] = \
str(app['instances'])
app['labels']['HAPROXY_DEPLOYMENT_COLOUR'] = colour
next_colour = 'blue'
next_port = get_service_port(app)
deployment_target_instances = app['instances']

app = set_app_ids(app, next_colour)
app = set_service_ports(app, next_port)
app['labels']['HAPROXY_DEPLOYMENT_TARGET_INSTANCES'] = \
str(deployment_target_instances)
app['labels']['HAPROXY_DEPLOYMENT_COLOUR'] = next_colour
app['labels']['HAPROXY_DEPLOYMENT_STARTED_AT'] = datetime.now().isoformat()
app['labels']['HAPROXY_0_PORT'] = str(service_port)

return app


def process_json(args, out=sys.stdout):
with open(args.json, 'r') as content_file:
content = content_file.read()

app = json.loads(content)
validate_app(app)

existing_apps = list_marathon_apps(args)
previous_deploys = \
select_previous_deploys(existing_apps, get_deployment_group(app))

if len(previous_deploys) > 1:
# There is a stuck deploy, oh no!
if args.resume:
logger.info("Found previous deployment, resuming")
old_deploy, current_deploy = \
select_last_two_deploys(previous_deploys)
start_deployment(args, current_deploy, old_deploy, True)
else:
raise Exception("There appears to be an"
" existing deployment in progress")

app = prepare_deploy(args, previous_deploys, app)

logger.info('Final app definition:')
out.write(json.dumps(app, sort_keys=True, indent=2))
Expand All @@ -387,7 +437,15 @@ def process_json(args, out=sys.stdout):
return

if args.force or query_yes_no("Continue with deployment?"):
start_deployment(args, app, existing_app, resuming)

if len(previous_deploys) == 0:
# This is the first deployment, no existing_app
start_deployment(args, app, None, False)

if len(previous_deploys) == 1:
# This is a standard blue/green deploy
existing_app = select_last_deploy(previous_deploys)
start_deployment(args, app, existing_app, False)


def get_arg_parser():
Expand Down

0 comments on commit c427f5c

Please sign in to comment.