Add support for rolling upgrade action

Depends-On: I8700d499168b560e1cfeb309b4eaae1bd9ddb995
Change-Id: Ifb3b2f36735932bafa5fb8a71892b0638eb11a2e
This commit is contained in:
Yuriy Taraday 2016-11-11 15:26:46 +03:00
parent 4f96245635
commit 2b15322c5f
2 changed files with 94 additions and 0 deletions

View File

@ -15,6 +15,7 @@ import etcd
import jinja2
import json
import netifaces
import pykube
import six
@ -345,6 +346,80 @@ def run_daemon(cmd, user=None):
raise RuntimeError("Process exited with code: %d" % proc.returncode)
def get_pykube_client():
os.environ['KUBERNETES_SERVICE_HOST'] = 'kubernetes.default'
config = pykube.KubeConfig.from_service_account()
return pykube.HTTPClient(config)
def _reload_obj(obj, updated_dict):
obj.reload()
obj.obj = updated_dict
def get_pykube_object(object_dict, namespace, client):
obj_class = getattr(pykube, object_dict["kind"], None)
if obj_class is None:
raise RuntimeError('"%s" object is not supported, skipping.'
% object_dict['kind'])
if not object_dict['kind'] == 'Namespace':
object_dict['metadata']['namespace'] = namespace
return obj_class(client, object_dict)
UPDATABLE_OBJECTS = ('ConfigMap', 'Deployment', 'Service')
def process_pykube_object(object_dict, namespace, client):
LOG.debug("Deploying %s: \"%s\"",
object_dict["kind"], object_dict["metadata"]["name"])
obj = get_pykube_object(object_dict, namespace, client)
if obj.exists():
LOG.debug('%s "%s" already exists', object_dict['kind'],
object_dict['metadata']['name'])
if object_dict['kind'] in UPDATABLE_OBJECTS:
if object_dict['kind'] == 'Service':
# Reload object and merge new and old fields
_reload_obj(obj, object_dict)
obj.update()
LOG.debug('%s "%s" has been updated', object_dict['kind'],
object_dict['metadata']['name'])
else:
obj.create()
LOG.debug('%s "%s" has been created', object_dict['kind'],
object_dict['metadata']['name'])
return obj
def wait_for_deployment(obj):
while True:
generation = obj.obj['metadata']['generation']
observed_generation = obj.obj['status']['observedGeneration']
if observed_generation >= generation:
break
LOG.info("Waiting for deployment %s to move to new generation")
time.sleep(4.2)
obj.reload()
while True:
desired = obj.obj['spec']['replicas']
status = obj.obj['status']
updated = status['updatedReplicas']
available = status['availableReplicas']
current = status['replicas']
if desired == updated == available == current:
break
LOG.info("Waiting for deployment %s: desired=%s, updated=%s,"
" available=%s, current=%s",
obj.obj['metadata']['name'],
desired, updated, available, current)
time.sleep(4.2)
obj.reload()
def get_workflow(role_name):
workflow_path = WORKFLOW_PATH_TEMPLATE % role_name
LOG.info("Getting workflow from %s", workflow_path)
@ -420,10 +495,13 @@ def do_provision(role_name):
job = workflow.get("job")
daemon = workflow.get("daemon")
roll = workflow.get("roll")
if job:
execute_job(workflow, job)
elif daemon:
execute_daemon(workflow, daemon)
elif roll is not None:
execute_roll(workflow, roll)
else:
LOG.error("Job or daemon is not specified in workflow")
sys.exit(1)
@ -460,5 +538,20 @@ def execute_job(workflow, job):
sys.exit(0)
def execute_roll(workflow, roll):
LOG.info("Running rolling upgrade of service %s", workflow["name"])
namespace = VARIABLES["namespace"]
client = get_pykube_client()
deployments = []
for object_dict in roll:
obj = process_pykube_object(object_dict, namespace, client)
if object_dict['kind'] == 'Deployment':
deployments.append(obj)
for obj in deployments:
wait_for_deployment(obj)
set_status_ready(workflow["name"])
sys.exit(0)
if __name__ == "__main__":
main()

View File

@ -4,6 +4,7 @@
pbr>=1.6 # Apache-2.0
Jinja2>=2.8 # BSD License (3 clause)
pykube
python-etcd>=0.4.3 # MIT License
PyYAML>=3.10.0 # MIT
six>=1.9.0 # MIT