diff --git a/CHANGELOG.md b/CHANGELOG.md index f1efb70f2..2dff469e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ Versioning](http://semver.org/spec/v2.0.0.html). - `marsha` - `edxec` - `edxapp` +- Introduce static services to expose services to other apps with a fixed name ### Changed diff --git a/Upgrade.md b/Upgrade.md new file mode 100644 index 000000000..28b1fa04f --- /dev/null +++ b/Upgrade.md @@ -0,0 +1,86 @@ +# Upgrade + +All instructions to upgrade this project from one release to the next will be +documented in this file. Upgrades must be run sequentially, meaning you should +not skip minor/major releases while upgrading (fix releases can be skipped). + +The format is inspired from [Keep a +Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to +[Semantic Versioning](https://semver.org/spec/v2.0.0.html). + + +## Unreleased + +### Static services + +This version introduces `Static services` and it is a breaking change in the +blue/green deployment process. The `switch` playbook is patching static services +instead of routes. And the `deployment_stamp` of the deployed stacks is no +longer stored in routes, but in static services instead. + +In order to migrate to this new system, you have to apply the following upgrade +process. This will not cause any downtime, but it implies a redeployment of your +applications. + +#### Upgrade Procedure + +This procedure must be applied for every arnold application deployed. + +The `current` stack of your application (before applying this procedure) will be +referenced as `BEFORE-UPGRADE-VERSION`. + + +##### 1. Upgrade your arnold version + +##### 2. Execute the `create_services` ansible playbook : + +``` +bin/ansible-playbook create_services.yml -e "apps_filter=your-application" +``` +It will create the static services required by your application. Each variant of these static services (`previous`, `current`, `next`) willtarget nothing after this step. + +##### 3. Execute the `deploy` ansible playbook : + +``` +bin/deploy -e "apps_filter=your-application" +``` + +It will deploy your application and the `next` static services will target this +stack. + +This step does not affect routes. So your `BEFORE-UPGRADE-VERSION` stays +unchanged and available via the `current` route. On the other hand, the `next` +stack you just deployed will not be reachable by any route. + +##### 4. Execute the `switch` ansible playbook : + +``` +bin/switch -e "apps_filter=your-application" +``` + +The switch will be done at a the static services level. So, the stack you just +deployed will be considered as the `current` by static services and by the +ansible playbooks. + +But again, this step does not affect routes. So your `BEFORE-UPGRADE-VERSION` +stack stays unchanged and available via the `current` route. + +##### 5. Execute the `create_routes` playbook : + +``` +bin/ansible-playbook create_routes.yml -e "apps_filter=your-application" +``` + +This will patch the routes to target the corresponding static services. After +this step, your `BEFORE-UPGRADE-VERSION` will be unavailable and will be +replaced by the `current` stack you just deployed. + + +##### 6. Check and clean + +Check that everything is OK and execute the `clean` playbook to remove +unreferenced stacks : + +``` +bin/clean -e "apps_filter=your-application" +``` \ No newline at end of file diff --git a/apps/edxapp/templates/services/nginx/route_cms.yml.j2 b/apps/edxapp/templates/services/nginx/route_cms.yml.j2 index c6a7239c3..1c5cfcd82 100644 --- a/apps/edxapp/templates/services/nginx/route_cms.yml.j2 +++ b/apps/edxapp/templates/services/nginx/route_cms.yml.j2 @@ -8,7 +8,6 @@ metadata: customer: "{{ customer }}" app: "edxapp" service: "nginx" - version: "{{ edxapp_nginx_image_tag }}" route_prefix: "{{ prefix }}" route_target_service: "cms" annotations: @@ -25,4 +24,4 @@ spec: targetPort: "{{ edxapp_nginx_cms_port }}-tcp" to: kind: Service - name: "edxapp-nginx-{{ deployment_stamp }}" + name: "edxapp-nginx-{{ prefix }}" diff --git a/apps/edxapp/templates/services/nginx/route_lms.yml.j2 b/apps/edxapp/templates/services/nginx/route_lms.yml.j2 index 379d21eef..cee442c26 100644 --- a/apps/edxapp/templates/services/nginx/route_lms.yml.j2 +++ b/apps/edxapp/templates/services/nginx/route_lms.yml.j2 @@ -8,7 +8,6 @@ metadata: customer: "{{ customer }}" app: "edxapp" service: "nginx" - version: "{{ edxapp_nginx_image_tag }}" route_prefix: "{{ prefix }}" route_target_service: "lms" annotations: @@ -25,4 +24,4 @@ spec: targetPort: "{{ edxapp_nginx_lms_port }}-tcp" to: kind: Service - name: "edxapp-nginx-{{ deployment_stamp }}" + name: "edxapp-nginx-{{ prefix }}" diff --git a/apps/edxapp/templates/services/nginx/route_preview.yml.j2 b/apps/edxapp/templates/services/nginx/route_preview.yml.j2 index 60c6f993e..93122a729 100644 --- a/apps/edxapp/templates/services/nginx/route_preview.yml.j2 +++ b/apps/edxapp/templates/services/nginx/route_preview.yml.j2 @@ -8,7 +8,6 @@ metadata: customer: "{{ customer }}" app: "edxapp" service: "nginx" - version: "{{ edxapp_nginx_image_tag }}" route_prefix: "{{ prefix }}" route_target_service: "lms" annotations: @@ -25,4 +24,4 @@ spec: targetPort: "{{ edxapp_nginx_lms_port }}-tcp" to: kind: Service - name: "edxapp-nginx-{{ deployment_stamp }}" + name: "edxapp-nginx-{{ prefix }}" diff --git a/apps/edxapp/templates/services/nginx/static-svc.yml.j2 b/apps/edxapp/templates/services/nginx/static-svc.yml.j2 new file mode 100644 index 000000000..1330f4384 --- /dev/null +++ b/apps/edxapp/templates/services/nginx/static-svc.yml.j2 @@ -0,0 +1,30 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app: edxapp + service: nginx + deployment_stamp: "{{ deployment_stamp }}" + service_prefix: "{{ prefix }}" + type: static-service + removable: "no" + name: "edxapp-nginx-{{ prefix }}" + namespace: "{{ project_name }}" +spec: + ports: + - name: "{{ edxapp_nginx_cms_port }}-tcp" + port: {{ edxapp_nginx_cms_port }} + protocol: TCP + targetPort: {{ edxapp_nginx_cms_port }} + - name: "{{ edxapp_nginx_lms_port }}-tcp" + port: {{ edxapp_nginx_lms_port }} + protocol: TCP + targetPort: {{ edxapp_nginx_lms_port }} + - name: "{{ edxapp_nginx_healthcheck_port }}-tcp" + port: {{ edxapp_nginx_healthcheck_port }} + protocol: TCP + targetPort: {{ edxapp_nginx_healthcheck_port }} + selector: + app: edxapp + deploymentconfig: "edxapp-nginx-{{ deployment_stamp | default('undefined', true) }}" + type: ClusterIP diff --git a/apps/edxec/templates/services/nginx/route.yml.j2 b/apps/edxec/templates/services/nginx/route.yml.j2 index 1a16cec82..cda0b0523 100644 --- a/apps/edxec/templates/services/nginx/route.yml.j2 +++ b/apps/edxec/templates/services/nginx/route.yml.j2 @@ -8,7 +8,6 @@ metadata: customer: "{{ customer }}" app: "edxec" service: "nginx" - version: "{{ edxec_nginx_image_tag }}" route_prefix: "{{ prefix }}" route_target_service: "app" annotations: @@ -24,4 +23,4 @@ spec: targetPort: "{{ edxec_nginx_port }}-tcp" to: kind: Service - name: "edxec-nginx-{{ deployment_stamp }}" + name: "edxec-nginx-{{ prefix }}" diff --git a/apps/edxec/templates/services/nginx/static-svc.yml.j2 b/apps/edxec/templates/services/nginx/static-svc.yml.j2 new file mode 100644 index 000000000..5b2c7fabc --- /dev/null +++ b/apps/edxec/templates/services/nginx/static-svc.yml.j2 @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app: edxec + service: nginx + deployment_stamp: "{{ deployment_stamp }}" + service_prefix: "{{ prefix }}" + type: static-service + removable: "no" + name: "edxec-nginx-{{ prefix }}" + namespace: "{{ project_name }}" +spec: + ports: + - name: {{ edxec_nginx_port }}-tcp + port: {{ edxec_nginx_port }} + protocol: TCP + targetPort: {{ edxec_nginx_port }} + - name: "{{ edxec_nginx_healthcheck_port }}-tcp" + port: {{ edxec_nginx_healthcheck_port }} + protocol: TCP + targetPort: {{ edxec_nginx_healthcheck_port }} + selector: + app: edxec + deploymentconfig: "edxec-nginx-{{ deployment_stamp | default('undefined', true) }}" + type: ClusterIP diff --git a/apps/forum/templates/services/app/route.yml.j2 b/apps/forum/templates/services/app/route.yml.j2 index 398212843..a0be95d93 100644 --- a/apps/forum/templates/services/app/route.yml.j2 +++ b/apps/forum/templates/services/app/route.yml.j2 @@ -8,7 +8,6 @@ metadata: customer: "{{ customer }}" app: "forum" service: "app" - version: "{{ forum_image_tag }}" route_prefix: "{{ prefix }}" route_target_service: "app" annotations: @@ -24,4 +23,4 @@ spec: targetPort: "{{ forum_port }}-tcp" to: kind: Service - name: "forum-app-{{ deployment_stamp }}" + name: "forum-app-{{ prefix }}" diff --git a/apps/forum/templates/services/app/static-svc.yml.j2 b/apps/forum/templates/services/app/static-svc.yml.j2 new file mode 100644 index 000000000..da56722ce --- /dev/null +++ b/apps/forum/templates/services/app/static-svc.yml.j2 @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app: forum + service: forum + deployment_stamp: "{{ deployment_stamp }}" + service_prefix: "{{ prefix }}" + type: static-service + removable: "no" + name: "forum-app-{{ prefix }}" + namespace: "{{ project_name }}" +spec: + ports: + - name: "{{ forum_port }}-tcp" + port: {{ forum_port }} + protocol: TCP + targetPort: {{ forum_port }} + selector: + app: forum + deploymentconfig: "forum-app-{{ deployment_stamp | default('undefined', true) }}" + type: ClusterIP diff --git a/apps/hello/templates/services/app/route.yml.j2 b/apps/hello/templates/services/app/route.yml.j2 index ace835209..19685d09f 100644 --- a/apps/hello/templates/services/app/route.yml.j2 +++ b/apps/hello/templates/services/app/route.yml.j2 @@ -21,4 +21,4 @@ spec: targetPort: "{{ hello_app_port }}-tcp" to: kind: Service - name: "hello-app-{{ deployment_stamp }}" + name: "hello-app-{{ prefix }}" diff --git a/apps/hello/templates/services/app/static-svc.yml.j2 b/apps/hello/templates/services/app/static-svc.yml.j2 new file mode 100644 index 000000000..be957f8e9 --- /dev/null +++ b/apps/hello/templates/services/app/static-svc.yml.j2 @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app: hello + deployment_stamp: "{{ deployment_stamp }}" + service_prefix: "{{ prefix }}" + type: static-service + removable: "no" + name: "hello-app-{{ prefix }}" + namespace: "{{ project_name }}" +spec: + ports: + - name: {{ hello_app_port }}-tcp + port: {{ hello_app_port }} + protocol: TCP + targetPort: {{ hello_app_port }} + type: ClusterIP + selector: + deploymentconfig: "hello-app-{{ deployment_stamp | default('undefined', true) }}" diff --git a/apps/learninglocker/templates/services/nginx/route.yml.j2 b/apps/learninglocker/templates/services/nginx/route.yml.j2 index 8b52df8b4..4ede05c3d 100644 --- a/apps/learninglocker/templates/services/nginx/route.yml.j2 +++ b/apps/learninglocker/templates/services/nginx/route.yml.j2 @@ -8,7 +8,6 @@ metadata: customer: "{{ customer }}" app: "learninglocker" service: "nginx" - version: "{{ learninglocker_nginx_image_tag }}" route_prefix: "{{ prefix }}" annotations: kubernetes.io/tls-acme: "true" @@ -23,4 +22,4 @@ spec: targetPort: "{{ learninglocker_nginx_port }}-tcp" to: kind: Service - name: "learninglocker-nginx-{{ deployment_stamp }}" + name: "learninglocker-nginx-{{ prefix }}" diff --git a/apps/learninglocker/templates/services/nginx/static-svc.yml.j2 b/apps/learninglocker/templates/services/nginx/static-svc.yml.j2 new file mode 100644 index 000000000..dbfe83a2f --- /dev/null +++ b/apps/learninglocker/templates/services/nginx/static-svc.yml.j2 @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app: learninglocker + service: nginx + deployment_stamp: "{{ deployment_stamp }}" + service_prefix: "{{ prefix }}" + type: static-service + removable: "no" + name: "learninglocker-nginx-{{ prefix }}" + namespace: "{{ project_name }}" +spec: + ports: + - name: "{{ learninglocker_nginx_port }}-tcp" + port: {{ learninglocker_nginx_port }} + protocol: TCP + targetPort: {{ learninglocker_nginx_port }} + - name: "{{ learninglocker_nginx_healthcheck_port }}-tcp" + port: {{ learninglocker_nginx_healthcheck_port }} + protocol: TCP + targetPort: {{ learninglocker_nginx_healthcheck_port }} + selector: + app: learninglocker + deploymentconfig: "learninglocker-nginx-{{ deployment_stamp | default('undefined', true) }}" + type: ClusterIP diff --git a/apps/marsha/templates/services/nginx/route.yml.j2 b/apps/marsha/templates/services/nginx/route.yml.j2 index 8d5d4eee6..e6f5b7661 100644 --- a/apps/marsha/templates/services/nginx/route.yml.j2 +++ b/apps/marsha/templates/services/nginx/route.yml.j2 @@ -8,7 +8,6 @@ metadata: customer: "{{ customer }}" app: "marsha" service: "nginx" - version: "{{ marsha_nginx_image_tag }}" route_prefix: "{{ prefix }}" route_target_service: "app" annotations: @@ -24,4 +23,4 @@ spec: targetPort: "{{ marsha_nginx_port }}-tcp" to: kind: Service - name: "marsha-nginx-{{ deployment_stamp }}" + name: "marsha-nginx-{{ prefix }}" diff --git a/apps/marsha/templates/services/nginx/static-svc.yml.j2 b/apps/marsha/templates/services/nginx/static-svc.yml.j2 new file mode 100644 index 000000000..864416d21 --- /dev/null +++ b/apps/marsha/templates/services/nginx/static-svc.yml.j2 @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app: marsha + service: nginx + deployment_stamp: "{{ deployment_stamp }}" + service_prefix: "{{ prefix }}" + type: static-service + removable: "no" + name: "marsha-nginx-{{ prefix }}" + namespace: "{{ project_name }}" +spec: + ports: + - name: {{ marsha_nginx_port }}-tcp + port: {{ marsha_nginx_port }} + protocol: TCP + targetPort: {{ marsha_nginx_port }} + - name: "{{ marsha_nginx_healthcheck_port }}-tcp" + port: {{ marsha_nginx_healthcheck_port }} + protocol: TCP + targetPort: {{ marsha_nginx_healthcheck_port }} + selector: + app: marsha + deploymentconfig: "marsha-nginx-{{ deployment_stamp | default('undefined', true) }}" + type: ClusterIP diff --git a/apps/richie/templates/services/nginx/route.yml.j2 b/apps/richie/templates/services/nginx/route.yml.j2 index 3d634cafe..582c9c161 100644 --- a/apps/richie/templates/services/nginx/route.yml.j2 +++ b/apps/richie/templates/services/nginx/route.yml.j2 @@ -8,7 +8,6 @@ metadata: customer: "{{ customer }}" app: "richie" service: "nginx" - version: "{{ richie_nginx_image_tag }}" route_prefix: "{{ prefix }}" route_target_service: "app" annotations: @@ -24,4 +23,4 @@ spec: targetPort: "{{ richie_nginx_port }}-tcp" to: kind: Service - name: "richie-nginx-{{ deployment_stamp }}" + name: "richie-nginx-{{ prefix }}" diff --git a/apps/richie/templates/services/nginx/static-svc.yml.j2 b/apps/richie/templates/services/nginx/static-svc.yml.j2 new file mode 100644 index 000000000..1288e5d2a --- /dev/null +++ b/apps/richie/templates/services/nginx/static-svc.yml.j2 @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app: richie + service: nginx + service_prefix: "{{ prefix }}" + deployment_stamp: "{{ deployment_stamp }}" + type: static-service + removable: "no" + name: "richie-nginx-{{ prefix }}" + namespace: "{{ project_name }}" +spec: + ports: + - name: {{ richie_nginx_port }}-tcp + port: {{ richie_nginx_port }} + protocol: TCP + targetPort: {{ richie_nginx_port }} + - name: "{{ richie_nginx_healthcheck_port }}-tcp" + port: {{ richie_nginx_healthcheck_port }} + protocol: TCP + targetPort: {{ richie_nginx_healthcheck_port }} + type: ClusterIP + selector: + app: richie + deploymentconfig: "richie-nginx-{{ deployment_stamp | default('undefined', true) }}" diff --git a/create_services.yml b/create_services.yml new file mode 100644 index 000000000..62ecd0795 --- /dev/null +++ b/create_services.yml @@ -0,0 +1,20 @@ +- hosts: local + gather_facts: False + + pre_tasks: + - import_tasks: tasks/check_configuration.yml + + tasks: + - name: Display playbook name + debug: msg="==== Starting create_services playbook ====" + tags: deploy + + - import_tasks: tasks/set_vars.yml + + - include_tasks: tasks/run_tasks_for_apps.yml + vars: + tasks: + - get_objects_for_app + - create_static_services + tags: + - static_service diff --git a/delete_previous.yml b/delete_previous.yml index 5b20a33ad..af8433bb4 100644 --- a/delete_previous.yml +++ b/delete_previous.yml @@ -21,9 +21,9 @@ vars: tasks: - get_objects_for_app - - deploy_get_stamp_from_route + - deploy_get_stamp_from_static_service - delete_app prefix: previous tags: - - route + - static_service - switch diff --git a/deploy.yml b/deploy.yml index 3f294e143..509572b66 100644 --- a/deploy.yml +++ b/deploy.yml @@ -46,15 +46,15 @@ - config - deploy - # Patch all next routes of all apps after deploy + # Patch all next static services of all apps after deploy - include_tasks: tasks/run_tasks_for_apps.yml vars: prefix: "next" tasks: - get_objects_for_app - - deploy_get_stamp_from_route - - deploy_patch_route + - deploy_get_stamp_from_static_service + - deploy_patch_static_service - delete_app tags: - - route + - static_service - deploy diff --git a/docs/developer_guide/concepts.md b/docs/developer_guide/concepts.md index 3645bd478..225ad8cc5 100644 --- a/docs/developer_guide/concepts.md +++ b/docs/developer_guide/concepts.md @@ -159,3 +159,99 @@ After running this playbook, the developer will be invited to manually: * customize variables and files as necessary, * commit everything to the repository. + +## Supported object kinds + +Arnold applications can declare various kind of objects that will be deployed on the +openshift cluster. + +### DeploymentConfig + +[DeploymentConfig](https://docs.openshift.com/container-platform/3.11/dev_guide/deployments/how_deployments_work.html) +objects are declared in jinja2 template files matching the pattern `dc*.yml.j2` . + +> Deployment configurations describe the desired state of a particular component of + the application as a pod template. + +For the purpose of our blue/green deployment process, the name of a +`DeploymentConfig` is dynamic: it is suffixed with a stamp that is unique to the version of the deployed application. + +### Service (aka `Blue/Green service`) + +[Service](https://kubernetes.io/docs/concepts/services-networking/service/) +objects are declared in jinja2 template files matching the pattern `svc*.yml.j2` + +They are part of our blue/green deployment process and their name are also dynamic: they are suffixed with a deployment stamp. +Each deployed version of an application has its own set of services and is referred to as a `stack`. + +Services allow components (i.e. `pods`) of a deployed application to communicate with each other while also +ensuring that the application stack is consistent. + +### Static Service + +*Static Service* objects are declared in jinja2 template files matching the pattern `static-svc*.yml.j2`. + +Technically, they are pure kubernetes [Service](https://kubernetes.io/docs/concepts/services-networking/service/) objects. +But in arnold, we use them for a specific case in our blue/green compatible applications. + +B/G Services are helpful for blue/green deployments and for internal communication inside the same application, but their dynamic name make it difficult to be used by other applications. +That's why we introduced static services. + +Static services, as their name suggests, are services with a name that does not change. + +Static services are declined in 3 variants (i.e. the static service `foo` is declined in `foo-previous`, `foo-current` and `foo-next`). +Each variant targets the corresponding stack. + +The 2 use cases for a static service are: + +- Exposing an application to another application +- Exposing an application to a route + +### Route + +[Route](https://docs.openshift.com/container-platform/3.11/architecture/networking/routes.html) +objects are declared in jinja2 template files matching the pattern `route*.yml.j2`. + +> An OpenShift Container Platform route exposes a service at a host name, such as www.example.com, so that external clients can reach it by name. + +If you want to expose your application to external clients via HTTP, you must declare a route. + +Routes work with static services in a blue/green compatible application. So you must declare a static service if you declare a route. + +Each route is declined in 3 variants: +i.e. if you declare a route `bar`, it is declined in `bar-previous`, `bar-current` and `bar-next`. + +And each variant targets the corresponding variant of the static service. + +### ConfigMap + +ConfigMaps are automagically generated if you create files in the `configs` directory of a service template. + +For example, if I create the file `apps/my-app/templates/services/my-service/config/test.yml.j2`, a ConfigMap will be generated with a key named `test.yml` and with the content of the rendered template as a `value`. + +This might change in the future. + +### Jobs + +[Job](https://docs.openshift.com/container-platform/3.11/dev_guide/jobs.html) +objects are declared in jinja2 template files matching the pattern `job_*.yml.j2`. + +They are launched when you deploy your application. + +They can be launched before (default) or after the deployment of your DeploymentConfigs. + +To run a job after the deployment, you must set a label `job_type: "post"` + +### BuildConfig + +[BuildConfig](https://docs.openshift.com/container-platform/3.11/dev_guide/dev_tutorials/openshift_pipeline.html) are declared in jinja2 template files matching the pattern `bc_*.yml.j2`. + +### ImageStream + +[ImageStream](https://docs.openshift.com/container-platform/3.11/architecture/core_concepts/builds_and_image_streams.html) are declared in jinja2 template files matching the pattern `is_*.yml.j2`. + +### Endpoint + +For specific cases (i.e. having a kubernetes service that targets a machine outside of the kubernetes cluster), we may want to declare a [Service](https://kubernetes.io/docs/concepts/services-networking/service/) without `selector`. + +In this case, we can manage the endpoints of the service by declaring them in jinja2 template files matching the pattern `ep*.yml.j2` diff --git a/group_vars/all/main.yml b/group_vars/all/main.yml index 761135105..aec3b1345 100644 --- a/group_vars/all/main.yml +++ b/group_vars/all/main.yml @@ -47,7 +47,7 @@ trashable_env_types: - "feature" # Blue/Green deployment route prefixes -blue_green_route_prefixes: +blue_green_prefixes: - "previous" - "current" - "next" diff --git a/init_project.yml b/init_project.yml index e35b99a28..937dbb082 100644 --- a/init_project.yml +++ b/init_project.yml @@ -6,4 +6,5 @@ - import_playbook: create_acme.yml - import_playbook: create_redirect.yml - import_playbook: create_routes.yml +- import_playbook: create_services.yml - import_playbook: create_image_streams.yml diff --git a/rollback.yml b/rollback.yml index 67787d399..268d8a637 100644 --- a/rollback.yml +++ b/rollback.yml @@ -22,7 +22,7 @@ vars: tasks: - get_objects_for_app - - rollback_routes + - rollback_static_services tags: - route - rollback diff --git a/switch.yml b/switch.yml index dc885f2e0..c7c016dce 100644 --- a/switch.yml +++ b/switch.yml @@ -1,9 +1,9 @@ --- -# This playbook switch all routes: -# 1. point the "previous" route to the stack that was pointed by the "current" route, -# 2. point the "current" route to the stack that was pointed by the "next" route, -# 3. delete the stack that was pointed by the "previous" route, -# 4. patch the next route to the init stamp +# This playbook switch all static services: +# 1. point the "previous" static service to the stack that was pointed by the "current" static service, +# 2. point the "current" static service to the stack that was pointed by the "next" static service, +# 3. delete the stack that was pointed by the "previous" static service, +# 4. patch the next static service to the init stamp - hosts: local gather_facts: False @@ -23,7 +23,7 @@ vars: tasks: - get_objects_for_app - - switch_routes + - switch_static_services tags: - - route + - static_service - switch diff --git a/tasks/clean_app_orphans.yml b/tasks/clean_app_orphans.yml index 8a539e000..c4d2787b8 100644 --- a/tasks/clean_app_orphans.yml +++ b/tasks/clean_app_orphans.yml @@ -1,7 +1,7 @@ --- # Remove orphan application stacks (i.e. outdated, unused objects) -- include_tasks: deploy_get_stamp_from_route.yml +- include_tasks: deploy_get_stamp_from_static_service.yml vars: prefix: "{{ item }}" loop: ["previous", "current", "next"] diff --git a/tasks/create_static_services.yml b/tasks/create_static_services.yml new file mode 100644 index 000000000..f4510f42e --- /dev/null +++ b/tasks/create_static_services.yml @@ -0,0 +1,10 @@ +--- +# Create static routes for services of an app + +- name: "Make sure static service exists for the '{{ app.name }}' app with all prefixes" + include_tasks: tasks/deploy_patch_static_service.yml + loop: "{{ blue_green_prefixes }}" + loop_control: + loop_var: prefix + when: static_services | length > 0 and app.settings.is_blue_green_compatible | default(True) + tags: static_service diff --git a/tasks/create_static_services_routes.yml b/tasks/create_static_services_routes.yml index 5b12649bf..4591fc37f 100644 --- a/tasks/create_static_services_routes.yml +++ b/tasks/create_static_services_routes.yml @@ -3,7 +3,7 @@ - name: "Make sure static route exists for the '{{ app.name }}' app with all prefixes" include_tasks: tasks/deploy_patch_route.yml - loop: "{{ blue_green_route_prefixes }}" + loop: "{{ blue_green_prefixes }}" loop_control: loop_var: prefix when: routes | length > 0 and app.settings.is_blue_green_compatible | default(True) diff --git a/tasks/delete_app_objects_kind.yml b/tasks/delete_app_objects_kind.yml index ca389d0c5..58b136529 100644 --- a/tasks/delete_app_objects_kind.yml +++ b/tasks/delete_app_objects_kind.yml @@ -7,6 +7,7 @@ label_selectors: - app={{ app.name }} - deployment_stamp={{ targeted_deployment_stamp }} + - removable!=no register: selected_objects tags: deploy @@ -28,6 +29,7 @@ label_selectors: - app={{ app.name }} - deployment_stamp={{ targeted_deployment_stamp }} + - removable!=no register: remaining_objects until: remaining_objects.failed == True or ( remaining_objects.resources | length ) == 0 retries: 120 diff --git a/tasks/deploy_get_stamp_from_route.yml b/tasks/deploy_get_stamp_from_route.yml index 56a64b902..e69de29bb 100644 --- a/tasks/deploy_get_stamp_from_route.yml +++ b/tasks/deploy_get_stamp_from_route.yml @@ -1,46 +0,0 @@ ---- -# Get deployment_stamp from a route - -# An application can define several routes (e.g. two services with two -# different routes). Our goal here is to get the deployment_stamp of a -# deployed stack by getting a route object. We first retrieve a route and -# then the service targeted by this route. TThis service will be labelled with the -# deploy_stamp we are looking for. -- name: Get route for application {{ app.name }} with prefix {{ prefix }} - k8s_info: - api_version: "v1" - namespace: "{{ project_name }}" - kind: "Route" - label_selectors: - - app={{ app.name }} - - route_prefix={{ prefix }} - register: app_route - when: routes | length > 0 and app.settings.is_blue_green_compatible | default(True) - -- name: Get targeted service - k8s_info: - api_version: "v1" - namespace: "{{ project_name }}" - kind: "Service" - name: "{{ ( app_route.resources | first ).spec.to.name }}" - register: targeted_service - when: app_route.resources is defined - -# app_deployment_stamp must be defined otherwise all script dependending on this one will fail -- name: Initialize app_deployment_stamp - set_fact: - app_deployment_stamp: "" - -- name: Set app_deployment_stamp - set_fact: - app_deployment_stamp: "{{ (targeted_service.resources | first ).metadata.labels.deployment_stamp | default(none) }}" - when: targeted_service.resources is defined and targeted_service.resources | length == 1 - -- name: "Set {{ prefix }}_app_deployment_stamp" - set_fact: - "{{ prefix }}_app_deployment_stamp": "{{ app_deployment_stamp }}" - -- name: Print app_deployment_stamp - debug: - msg: "[{{ app.name }}] app_deployment_stamp[{{ app_deployment_stamp }}]" - when: app_deployment_stamp is defined diff --git a/tasks/deploy_get_stamp_from_static_service.yml b/tasks/deploy_get_stamp_from_static_service.yml new file mode 100644 index 000000000..081fb4a12 --- /dev/null +++ b/tasks/deploy_get_stamp_from_static_service.yml @@ -0,0 +1,37 @@ +--- +# Get deployment_stamp from a static service + +# An application can define several static services. (e.g. two static services with +# two different routes). Our goal here is to get the deployment_stamp of a +# deployed stack by getting a service object. We retrieve the service and it will +# be labelled with the deploy_stamp we are looking for. +- name: Get static service for application {{ app.name }} with prefix {{ prefix }} + k8s_info: + api_version: "v1" + namespace: "{{ project_name }}" + kind: "Service" + label_selectors: + - type=static-service + - app={{ app.name }} + - service_prefix={{ prefix }} + register: app_service + when: static_services | length > 0 and app.settings.is_blue_green_compatible | default(True) + +# app_deployment_stamp must be defined otherwise all script dependending on this one will fail +- name: Initialize app_deployment_stamp + set_fact: + app_deployment_stamp: "" + +- name: Set app_deployment_stamp + set_fact: + app_deployment_stamp: "{{ (app_service.resources | first ).metadata.labels.deployment_stamp | default(none) }}" + when: app_service.resources is defined and app_service.resources | length >= 1 + +- name: "Set {{ prefix }}_app_deployment_stamp" + set_fact: + "{{ prefix }}_app_deployment_stamp": "{{ app_deployment_stamp }}" + +- name: Print app_deployment_stamp + debug: + msg: "[{{ app.name }}] app_deployment_stamp[{{ app_deployment_stamp }}]" + when: app_deployment_stamp is defined diff --git a/tasks/deploy_patch_static_service.yml b/tasks/deploy_patch_static_service.yml new file mode 100644 index 000000000..08e5bf4b5 --- /dev/null +++ b/tasks/deploy_patch_static_service.yml @@ -0,0 +1,23 @@ +# Patch services of all services from a single app to the new deployment_stamp + +- name: "Patching services with prefix {{ prefix }} for the {{ app.name }} application with deployment_stamp {{ deployment_stamp }}" + k8s: + force: "{{ force_route | bool }}" + definition: "{{ lookup('template', service_template) | from_yaml }}" + state: present + loop: "{{ static_services }}" + loop_control: + loop_var: service_template + when: static_services | length > 0 and app.settings.is_blue_green_compatible | default(True) == True + tags: static_service + +- name: "Patching services for the {{ app.name }} application" + k8s: + force: "{{ force_route | bool }}" + definition: "{{ lookup('template', service_template) | from_yaml }}" + state: present + loop: "{{ static_services }}" + loop_control: + loop_var: service_template + when: static_services | length > 0 and app.settings.is_blue_green_compatible | default(True) == False + tags: static_service diff --git a/tasks/get_objects_for_app.yml b/tasks/get_objects_for_app.yml index 25904d23c..6fcdd14b5 100644 --- a/tasks/get_objects_for_app.yml +++ b/tasks/get_objects_for_app.yml @@ -18,6 +18,7 @@ deployments: "{{ templates | map('regex_search', '.*/dc.*\\.yml\\.j2$') | select('string') | list }}" endpoints: "{{ templates | map('regex_search', '.*/ep.*\\.yml\\.j2$') | select('string') | list }}" services: "{{ templates | map('regex_search', '.*/svc.*\\.yml\\.j2$') | select('string') | list }}" + static_services: "{{ templates | map('regex_search', '.*/static-svc.*\\.yml\\.j2$') | select('string') | list }}" streams: "{{ templates | map('regex_search', '.*/is.*\\.yml\\.j2$') | select('string') | list }}" jobs: "{{ templates | map('regex_search', '.*/job_.*\\.yml\\.j2$') | select('string') | list }}" routes: "{{ templates | map('regex_search', '.*/route.*\\.yml\\.j2$') | select('string') | list }}" diff --git a/tasks/rollback_routes.yml b/tasks/rollback_static_services.yml similarity index 55% rename from tasks/rollback_routes.yml rename to tasks/rollback_static_services.yml index e76161690..b0208f8d6 100644 --- a/tasks/rollback_routes.yml +++ b/tasks/rollback_static_services.yml @@ -1,15 +1,15 @@ --- -# Patch app dest routes with src stack +# Patch app dest static service with src stack -- include_tasks: deploy_get_stamp_from_route.yml +- include_tasks: deploy_get_stamp_from_static_service.yml vars: prefix: next tags: switch -- include_tasks: switch_route.yml +- include_tasks: switch_static_service.yml vars: - prefix_route_src: "{{ prefix_route.src }}" - prefix_route_dest: "{{ prefix_route.dest }}" + prefix_service_src: "{{ prefix_service.src }}" + prefix_service_dest: "{{ prefix_service.dest }}" update_src: "{{ prefix_route.update_src | default(True)}}" with_items: - src: current @@ -18,7 +18,7 @@ - src: previous dest: current loop_control: - loop_var: prefix_route + loop_var: prefix_service - include_tasks: delete_app.yml vars: diff --git a/tasks/switch_route.yml b/tasks/switch_route.yml deleted file mode 100644 index 22ef0e4d5..000000000 --- a/tasks/switch_route.yml +++ /dev/null @@ -1,24 +0,0 @@ ---- -# Patch app dest route with src stack - -- name: Print switch details - debug: msg="[{{ app.name }}] Switch routes from {{ prefix_route_src }} to {{ prefix_route_dest }}" - tags: switch - -- include_tasks: deploy_get_stamp_from_route.yml - vars: - prefix: "{{ prefix_route_src }}" - tags: switch - -- include_tasks: deploy_patch_route.yml - vars: - prefix: "{{ prefix_route_dest }}" - deployment_stamp: "{{ app_deployment_stamp }}" - tags: switch - -- include_tasks: deploy_patch_route.yml - vars: - prefix: "{{ prefix_route_src }}" - tags: switch - when: update_src is defined and update_src == True - diff --git a/tasks/switch_static_service.yml b/tasks/switch_static_service.yml new file mode 100644 index 000000000..c46d77bd2 --- /dev/null +++ b/tasks/switch_static_service.yml @@ -0,0 +1,23 @@ +--- +# Patch app dest static service with src stack + +- name: Print switch details + debug: msg="[{{ app.name }}] Switch static service from {{ prefix_service_src }} to {{ prefix_service_dest }}" + tags: switch + +- include_tasks: deploy_get_stamp_from_static_service.yml + vars: + prefix: "{{ prefix_service_src }}" + tags: switch + +- include_tasks: deploy_patch_static_service.yml + vars: + prefix: "{{ prefix_service_dest }}" + deployment_stamp: "{{ app_deployment_stamp }}" + tags: switch + +- include_tasks: deploy_patch_static_service.yml + vars: + prefix: "{{ prefix_service_src }}" + tags: switch + when: update_src is defined and update_src == True diff --git a/tasks/switch_routes.yml b/tasks/switch_static_services.yml similarity index 59% rename from tasks/switch_routes.yml rename to tasks/switch_static_services.yml index 7fae18090..13f680609 100644 --- a/tasks/switch_routes.yml +++ b/tasks/switch_static_services.yml @@ -1,12 +1,12 @@ --- -# Patch app dest routes with src stack +# Patch app dest static services with src stack -- include_tasks: deploy_get_stamp_from_route.yml +- include_tasks: deploy_get_stamp_from_static_service.yml vars: prefix: "previous" tags: switch -- include_tasks: deploy_get_stamp_from_route.yml +- include_tasks: deploy_get_stamp_from_static_service.yml vars: prefix: "next" tags: switch @@ -15,10 +15,10 @@ msg: "next stack is not deployed, aborting switch" when: next_app_deployment_stamp == '' -- include_tasks: switch_route.yml +- include_tasks: switch_static_service.yml vars: - prefix_route_src: "{{ prefix_route.src }}" - prefix_route_dest: "{{ prefix_route.dest }}" + prefix_service_src: "{{ prefix_service.src }}" + prefix_service_dest: "{{ prefix_service.dest }}" update_src: "{{ prefix_route.update_src | default(True)}}" with_items: - src: current @@ -27,7 +27,7 @@ - src: next dest: current loop_control: - loop_var: prefix_route + loop_var: prefix_service - include_tasks: delete_app.yml vars: