Adjust Ironic formula granularity
Change-Id: I9073326380278c71573f102d3b278be6c745696e
Related-PROD: PROD-21936
diff --git a/README.rst b/README.rst
index 4d76b85..218c333 100644
--- a/README.rst
+++ b/README.rst
@@ -229,3 +229,69 @@
pool_size: 5
sleep_time: 10
timeout: 15
+
+Upgrades
+========
+
+Each openstack formula provide set of phases (logical blocks) that will help to
+build flexible upgrade orchestration logic for particular components. The list
+of phases and theirs descriptions are listed in table below:
+
++-------------------------------+------------------------------------------------------+
+| State | Description |
++===============================+======================================================+
+| <app>.upgrade.service_running | Ensure that all services for particular application |
+| | are enabled for autostart and running |
++-------------------------------+------------------------------------------------------+
+| <app>.upgrade.service_stopped | Ensure that all services for particular application |
+| | disabled for autostart and dead |
++-------------------------------+------------------------------------------------------+
+| <app>.upgrade.pkgs_latest | Ensure that packages used by particular application |
+| | are installed to latest available version. |
+| | This will not upgrade data plane packages like qemu |
+| | and openvswitch as usually minimal required version |
+| | in openstack services is really old. The data plane |
+| | packages should be upgraded separately by `apt-get |
+| | upgrade` or `apt-get dist-upgrade` |
+| | Applying this state will not autostart service. |
++-------------------------------+------------------------------------------------------+
+| <app>.upgrade.render_config | Ensure configuration is rendered actual version. +
++-------------------------------+------------------------------------------------------+
+| <app>.upgrade.pre | We assume this state is applied on all nodes in the |
+| | cloud before running upgrade. |
+| | Only non destructive actions will be applied during |
+| | this phase. Perform service built in service check |
+| | like (keystone-manage doctor and nova-status upgrade)|
++-------------------------------+------------------------------------------------------+
+| <app>.upgrade.upgrade.pre | Mostly applicable for data plane nodes. During this |
+| | phase resources will be gracefully removed from |
+| | current node if it is allowed. Services for upgraded |
+| | application will be set to admin disabled state to |
+| | make sure node will not participate in resources |
+| | scheduling. For example on gtw nodes this will set |
+| | all agents to admin disable state and will move all |
+| | routers to other agents. |
++-------------------------------+------------------------------------------------------+
+| <app>.upgrade.upgrade | This state will basically upgrade application on |
+| | particular target. Stop services, render |
+| | configuration, install new packages, run offline |
+| | dbsync (for ctl), start services. Data plane should |
+| | not be affected, only OpenStack python services. |
++-------------------------------+------------------------------------------------------+
+| <app>.upgrade.upgrade.post | Add services back to scheduling. |
++-------------------------------+------------------------------------------------------+
+| <app>.upgrade.post | This phase should be launched only when upgrade of |
+| | the cloud is completed. Cleanup temporary files, |
+| | perform other post upgrade tasks. |
++-------------------------------+------------------------------------------------------+
+| <app>.upgrade.verify | Here we will do basic health checks (API CRUD |
+| | operations, verify do not have dead network |
+| | agents/compute services) |
++-------------------------------+------------------------------------------------------+
+
+Upgrade pillar example:
+ironic:
+ upgrade:
+ enabled: True
+ old_release: pike
+ new_release: queens
diff --git a/ironic/db/offline_sync.sls b/ironic/db/offline_sync.sls
index 5008575..71c5498 100644
--- a/ironic/db/offline_sync.sls
+++ b/ironic/db/offline_sync.sls
@@ -1,8 +1,11 @@
{%- from "ironic/map.jinja" import api with context %}
+{%- set should_run = '/bin/false' %}
+{%- if not grains.get('noservices') or api.get('role', 'secondary') == 'primary' %}
+{%- set should_run = '/bin/true' %}
+{%- endif %}
+
ironic_install_database:
cmd.run:
- name: ironic-dbsync --config-file /etc/ironic/ironic.conf upgrade
- {%- if grains.get('noservices') or ( api.api_type in ["deploy"] and api.get('role', 'primary') == 'secondary' ) %}
- - onlyif: /bin/false
- {%- endif %}
+ - onlyif: {{ should_run }}
diff --git a/ironic/db/online_sync.sls b/ironic/db/online_sync.sls
index 9008da9..14e0d9f 100644
--- a/ironic/db/online_sync.sls
+++ b/ironic/db/online_sync.sls
@@ -1,8 +1,12 @@
{%- from "ironic/map.jinja" import api with context %}
+{%- set should_run = '/bin/false' %}
+{%- if not grains.get('noservices') and api.version not in ["juno", "kilo", "liberty", 'ocata'] and api.api_type not in ["deploy"] and api.get('role', 'primary') == 'primary' %}
+{%- set should_run = '/bin/true' %}
+{%- endif %}
+
ironic_online_data_migrations:
cmd.run:
- name: ironic-dbsync online_data_migrations
- {%- if grains.get('noservices') or ( api.api_type in ["deploy"] and api.get('role', 'primary') == 'secondary' ) %}
- - onlyif: /bin/false
- {%- endif %}
+ - onlyif: {{ should_run }}
+ - runas: 'ironic'
diff --git a/ironic/meta/salt.yml b/ironic/meta/salt.yml
new file mode 100644
index 0000000..3e358ec
--- /dev/null
+++ b/ironic/meta/salt.yml
@@ -0,0 +1,5 @@
+orchestration:
+ upgrade:
+ applications:
+ ironic:
+ priority: 1070
diff --git a/ironic/upgrade/pkgs_latest.sls b/ironic/upgrade/pkgs_latest.sls
new file mode 100644
index 0000000..bc9d8ee
--- /dev/null
+++ b/ironic/upgrade/pkgs_latest.sls
@@ -0,0 +1,37 @@
+{%- from "ironic/map.jinja" import api,conductor,client with context %}
+
+ironic_task_pkg_latest:
+ test.show_notification:
+ - text: "Running ironic.upgrade.pkg_latest"
+
+policy-rc.d_present:
+ file.managed:
+ - name: /usr/sbin/policy-rc.d
+ - mode: 755
+ - contents: |
+ #!/bin/sh
+ exit 101
+
+{%- set pkgs = [] %}
+{%- if api.get('enabled', False) %}
+ {%- do pkgs.extend(api.pkgs) %}
+{%- endif %}
+{%- if conductor.get('enabled', False) %}
+ {%- do pkgs.extend(['ironic-conductor']) %}
+{%- endif %}
+{%- if client.get('enabled', False) %}
+ {%- do pkgs.extend(client.pkgs) %}
+{%- endif %}
+
+ironic_pkg_latest:
+ pkg.latest:
+ - names: {{ pkgs|unique }}
+ - require:
+ - file: policy-rc.d_present
+ - require_in:
+ - file: policy-rc.d_absent
+
+policy-rc.d_absent:
+ file.absent:
+ - name: /usr/sbin/policy-rc.d
+
diff --git a/ironic/upgrade/post/init.sls b/ironic/upgrade/post/init.sls
new file mode 100644
index 0000000..1a3737c
--- /dev/null
+++ b/ironic/upgrade/post/init.sls
@@ -0,0 +1,8 @@
+ironic_post:
+ test.show_notification:
+ - text: "Running ironic.upgrade.post"
+
+include:
+ - ironic.upgrade.render_config
+ - ironic.upgrade.service_stopped
+ - ironic.upgrade.service_running
diff --git a/ironic/upgrade/pre/init.sls b/ironic/upgrade/pre/init.sls
new file mode 100644
index 0000000..59c7e14
--- /dev/null
+++ b/ironic/upgrade/pre/init.sls
@@ -0,0 +1,71 @@
+{%- from "ironic/map.jinja" import api,conductor, client with context %}
+
+{%- if api.get("enabled", False) %}
+ {%- set ironic, service_name = api, 'api' %}
+{%- elif conductor.get('enabled', False) %}
+ {%- set ironic, service_name = conductor, 'conductor' %}
+{%- endif %}
+
+ironic_pre:
+ test.show_notification:
+ - text: "Running ironic.upgrade.pre"
+
+/etc/ironic/ironic.conf:
+ file.managed:
+ - source: salt://ironic/files/{{ ironic.version }}/ironic.conf
+ - template: jinja
+
+include:
+ - ironic.db.online_sync
+
+{%- set os_content = salt['mine.get']('I@keystone:client:os_client_config:enabled:true', 'keystone_os_client_config', 'compound').values()[0] %}
+keystone_os_client_config:
+ file.managed:
+ - name: /etc/openstack/clouds.yml
+ - contents: |
+ {{ os_content |yaml(False)|indent(8) }}
+ - user: 'root'
+ - group: 'root'
+ - makedirs: True
+ - unless: test -f /etc/openstack/clouds.yml
+
+{%- if conductor.get('enabled', false) %}
+ {%- if conductor.http_images is defined %}
+ {%- for image in conductor.http_images %}
+
+image_{{ image.name }}:
+ file.managed:
+ - name: {{ conductor.http_root }}/{{ image.name }}
+ - source: {{ image.source }}
+ {%- if image.md5summ is defined %}
+ - source_hash: md5={{ image.md5summ }}
+ {%- else %}
+ - source_hash: {{ image.hash_file }}
+ {%- endif %}
+ - user: 'ironic'
+ - group: 'ironic'
+ {%- endfor %}
+ {%- endif %}
+ {%- if client.get('enabled', false) %}
+ {%- for identity_name, nodes in client.nodes.iteritems() %}
+ {%- for node in nodes %}
+node_{{ node.name }}_present:
+ ironicv1.node_present:
+ - name: {{ node.name }}
+ - driver: {{ node.driver }}
+ - driver_info: {{ node.driver_info|default({}) }}
+ - cloud_name: {{ client.cloud_name }}
+ - properties: {{ node.properties|default({}) }}
+ {%- if node.network_interface is defined %}
+ - network_interface: {{ node.network_interface }}
+ {%- endif %}
+ {%- if node.storage_interface is defined %}
+ - storage_interface: {{ node.storage_interface }}
+ {%- endif %}
+ {%- if node.microversion is defined %}
+ - microversion: "{{ node.microversion }}"
+ {%- endif %}
+ {%- endfor %} # end for nodes
+ {%- endfor %} # end client.nodes.iteritems
+ {%- endif %}
+{%- endif %}
diff --git a/ironic/upgrade/render_config.sls b/ironic/upgrade/render_config.sls
new file mode 100644
index 0000000..d8ddac4
--- /dev/null
+++ b/ironic/upgrade/render_config.sls
@@ -0,0 +1,16 @@
+{%- from "ironic/map.jinja" import api,conductor with context %}
+
+{%- if api.get("enabled", False) %}
+ {%- set ironic, service_name = api, 'api' %}
+{%- elif conductor.get('enabled', False) %}
+ {%- set ironic, service_name = conductor, 'conductor' %}
+{%- endif %}
+
+ironic_render_config:
+ test.show_notification:
+ - text: "Running ironic.upgrade.render_config"
+
+/etc/ironic/ironic.conf:
+ file.managed:
+ - source: salt://ironic/files/{{ ironic.version }}/ironic.conf
+ - template: jinja
diff --git a/ironic/upgrade/service_running.sls b/ironic/upgrade/service_running.sls
new file mode 100644
index 0000000..b965cf3
--- /dev/null
+++ b/ironic/upgrade/service_running.sls
@@ -0,0 +1,19 @@
+{%- from "ironic/map.jinja" import api,conductor with context %}
+
+ironic_task_service_running:
+ test.show_notification:
+ - text: "Running ironic.upgrade.service_running"
+
+{%- if api.get('enabled', False) %}
+ironic_start_{{ api.service }}:
+ service.running:
+ - name: {{ api.service }}
+ - enable: True
+{%- endif %}
+
+{%- if conductor.get('enabled', False) %}
+ironic_start_{{ conductor.service }}:
+ service.running:
+ - name: {{ conductor.service }}
+ - enable: True
+{%- endif %}
diff --git a/ironic/upgrade/service_stopped.sls b/ironic/upgrade/service_stopped.sls
new file mode 100644
index 0000000..f0a8a18
--- /dev/null
+++ b/ironic/upgrade/service_stopped.sls
@@ -0,0 +1,19 @@
+{%- from "ironic/map.jinja" import api,conductor with context %}
+
+ironic_task_service_stopped:
+ test.show_notification:
+ - text: "Running ironic.upgrade.service_stopped"
+
+{%- if api.get('enabled', False) %}
+ironic_stop_{{ api.service }}:
+ service.dead:
+ - name: {{ api.service }}
+ - enable: False
+{%- endif %}
+
+{%- if conductor.get('enabled', False) %}
+ironic_stop_{{ conductor.service }}:
+ service.dead:
+ - name: {{ conductor.service }}
+ - enable: False
+{%- endif %}
diff --git a/ironic/upgrade/upgrade/init.sls b/ironic/upgrade/upgrade/init.sls
new file mode 100644
index 0000000..deb652b
--- /dev/null
+++ b/ironic/upgrade/upgrade/init.sls
@@ -0,0 +1,10 @@
+{%- from "ironic/map.jinja" import api with context %}
+
+include:
+ - ironic.upgrade.service_stopped
+ - ironic.upgrade.pkgs_latest
+ - ironic.upgrade.render_config
+{%- if api.get('enabled', False) %}
+ - ironic.db.offline_sync
+{%- endif %}
+ - ironic.upgrade.service_running
diff --git a/ironic/upgrade/upgrade/post.sls b/ironic/upgrade/upgrade/post.sls
new file mode 100644
index 0000000..48b7618
--- /dev/null
+++ b/ironic/upgrade/upgrade/post.sls
@@ -0,0 +1,4 @@
+ironic_upgrade_uprade_post:
+ test.show_notification:
+ - name: "dump_message_upgrade_ironic_post"
+ - text: "Running ironic.upgrade.upgrade.post"
diff --git a/ironic/upgrade/upgrade/pre.sls b/ironic/upgrade/upgrade/pre.sls
new file mode 100644
index 0000000..6d43585
--- /dev/null
+++ b/ironic/upgrade/upgrade/pre.sls
@@ -0,0 +1,4 @@
+ironic_upgrade_upgrade_pre:
+ test.show_notification:
+ - name: "dump_message_upgrade_ironic_pre"
+ - text: "Running ironic.upgrade.upgrade.pre"
diff --git a/ironic/upgrade/verify/_api.sls b/ironic/upgrade/verify/_api.sls
new file mode 100644
index 0000000..0628188
--- /dev/null
+++ b/ironic/upgrade/verify/_api.sls
@@ -0,0 +1,36 @@
+{%- from "ironic/map.jinja" import api with context %}
+{%- set Ironic_Test_Node_ID = salt['cmd.run']('cat /proc/sys/kernel/random/uuid') %}
+
+ironic_upgrade_verify_api:
+ test.show_notification:
+ - text: "Running ironic.upgrade.verify.api"
+
+{%- if api.api_type not in ["deploy"] and api.get('role', 'secondary') == 'primary' %}
+ironicv1_node_present_update:
+ ironicv1.node_present:
+ - name: test
+ - cloud_name: admin_identity
+ - driver: fake
+ - uuid: {{ Ironic_Test_Node_ID }}
+ - extra:
+ a: b
+ - microversion: "1.34"
+
+ironicv1_port_present:
+ ironicv1.port_present:
+ - cloud_name: admin_identity
+ - node: test
+ - address: "11:11:11:11:11:11"
+
+ironicv1_port_absent:
+ ironicv1.port_absent:
+ - cloud_name: admin_identity
+ - node: test
+ - address: "11:11:11:11:11:11"
+
+ironicv1_node_absent:
+ ironicv1.node_absent:
+ - cloud_name: admin_identity
+ - name: test
+
+{%- endif %}
diff --git a/ironic/upgrade/verify/init.sls b/ironic/upgrade/verify/init.sls
new file mode 100644
index 0000000..1f15e84
--- /dev/null
+++ b/ironic/upgrade/verify/init.sls
@@ -0,0 +1,2 @@
+include:
+ - ironic.upgrade.verify._api