Add octavia upgrade states

Change-Id: I51c84da6116db919464873a4247b6193c2a4d46c
Related-Prod: PROD-22187
diff --git a/.travis.yml b/.travis.yml
index 2356431..e599324 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -20,9 +20,6 @@
   - bundle install
 
 env:
-  - PLATFORM=epcim/salt:saltstack-ubuntu-xenial-salt-2016.3 SUITE=api-single
-  - PLATFORM=epcim/salt:saltstack-ubuntu-xenial-salt-2016.3 SUITE=api-cluster
-  - PLATFORM=epcim/salt:saltstack-ubuntu-xenial-salt-2016.3 SUITE=manager-single
   - PLATFORM=epcim/salt:saltstack-ubuntu-xenial-salt-2017.7 SUITE=api-single
   - PLATFORM=epcim/salt:saltstack-ubuntu-xenial-salt-2017.7 SUITE=api-cluster
   - PLATFORM=epcim/salt:saltstack-ubuntu-xenial-salt-2017.7 SUITE=manager-single
diff --git a/README.rst b/README.rst
index 0a9f5a1..e1d5990 100644
--- a/README.rst
+++ b/README.rst
@@ -135,6 +135,62 @@
           group: octavia
 
 
+Upgrades
+========
+ Each openstack formula provide set of phases (logical bloks) that will help to
+build flexible upgrade orchestration logic for particular components. The list
+of phases might 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.pkg_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.                              |
++-------------------------------+------------------------------------------------------+
+| <app>.upgrade.verify          | Here we will do basic health checks (API CRUD        |
+|                               | operations, verify do not have dead network          |
+|                               | agents/compute services)                             |
++-------------------------------+------------------------------------------------------+
+
 
 More information
 ================
diff --git a/octavia/api.sls b/octavia/api.sls
index 072bdcb..c429cd0 100644
--- a/octavia/api.sls
+++ b/octavia/api.sls
@@ -2,9 +2,14 @@
 
 {%- if api.enabled %}
 
+include:
+  - octavia.db.offline_sync
+
 octavia_api_packages:
   pkg.installed:
   - names: {{ api.pkgs }}
+  - require_in:
+    - sls: octavia.db.offline_sync
 
 
 /etc/octavia/octavia_api.conf:
@@ -13,6 +18,8 @@
   - template: jinja
   - require:
     - pkg: octavia_api_packages
+  - require_in:
+    - sls: octavia.db.offline_sync
 
 {%- if pillar.octavia.manager is not defined %}
 /etc/octavia/certificates/openssl.cnf:
@@ -28,13 +35,6 @@
     - pkg: octavia_api_packages
 {%- endif %}
 
-{%- if not grains.get('noservices', False) %}
-octavia_db_manage:
-  cmd.run:
-  - name: octavia-db-manage --config-file /etc/octavia/octavia_api.conf upgrade head
-  - require:
-    - file: /etc/octavia/octavia_api.conf
-{%- endif %}
 
 {%- if not grains.get('noservices', False) %}
 octavia_api_services:
@@ -44,7 +44,7 @@
   - watch:
     - file: /etc/octavia/octavia_api.conf
   - require:
-    - cmd: octavia_db_manage
+    - sls: octavia.db.offline_sync
 {%- endif %}
 
 {%- endif %}
diff --git a/octavia/db/offline_sync.sls b/octavia/db/offline_sync.sls
new file mode 100644
index 0000000..272ef86
--- /dev/null
+++ b/octavia/db/offline_sync.sls
@@ -0,0 +1,8 @@
+{%- from "octavia/map.jinja" import api with context %}
+
+octavia_db_manage:
+  cmd.run:
+  - name: octavia-db-manage --config-file /etc/octavia/octavia_api.conf upgrade head
+  {%- if grains.get('noservices') or api.get('role', 'primary') == 'secondary' %}
+  - onlyif: /bin/false
+  {%- endif %}
diff --git a/octavia/meta/salt.yml b/octavia/meta/salt.yml
new file mode 100644
index 0000000..2f4ec45
--- /dev/null
+++ b/octavia/meta/salt.yml
@@ -0,0 +1,5 @@
+orchestration:
+  upgrade:
+    applications:
+      octavia:
+        priority: 1180
\ No newline at end of file
diff --git a/octavia/upgrade/pkgs_latest.sls b/octavia/upgrade/pkgs_latest.sls
new file mode 100644
index 0000000..5b4e3d3
--- /dev/null
+++ b/octavia/upgrade/pkgs_latest.sls
@@ -0,0 +1,36 @@
+{%- from "octavia/map.jinja" import api,manager,client with context %}
+
+octavia_task_pkg_latest:
+  test.show_notification:
+    - text: "Running octavia.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.enabled %}
+  {%- do pkgs.extend(api.pkgs) %}
+{%- endif %}
+{%- if manager.enabled %}
+  {%- do pkgs.extend(manager.pkgs) %}
+{%- endif %}
+{%- if client.enabled %}
+  {%- do pkgs.extend(client.pkgs) %}
+{%- endif %}
+
+octavia_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/octavia/upgrade/post/init.sls b/octavia/upgrade/post/init.sls
new file mode 100644
index 0000000..4cd8869
--- /dev/null
+++ b/octavia/upgrade/post/init.sls
@@ -0,0 +1,7 @@
+octavia_post:
+  test.show_notification:
+    - text: "Running octavia.upgrade.post"
+
+keystone_os_client_config_absent:
+  file.absent:
+    - name: /etc/openstack/clouds.yml
diff --git a/octavia/upgrade/pre/init.sls b/octavia/upgrade/pre/init.sls
new file mode 100644
index 0000000..a43e671
--- /dev/null
+++ b/octavia/upgrade/pre/init.sls
@@ -0,0 +1,14 @@
+octavia_pre:
+  test.show_notification:
+    - text: "Running octavia.upgrade.pre"
+
+{%- 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
\ No newline at end of file
diff --git a/octavia/upgrade/render_config.sls b/octavia/upgrade/render_config.sls
new file mode 100644
index 0000000..3dc9bfb
--- /dev/null
+++ b/octavia/upgrade/render_config.sls
@@ -0,0 +1,41 @@
+{%- from "octavia/map.jinja" import api,manager with context %}
+
+octavia_render_config:
+  test.show_notification:
+    - text: "Running octavia.upgrade.render_config"
+
+/etc/octavia/certificates/openssl.cnf:
+  file.managed:
+  - source: salt://octavia/files/{{ api.version }}/certificates/openssl.cnf
+
+{%- if api.enabled %}
+/etc/octavia/octavia_api.conf:
+  file.managed:
+  - source: salt://octavia/files/{{ api.version }}/octavia_api.conf
+  - template: jinja
+{%- endif %}
+
+{%- if manager.enabled %}
+{%- set ssh_dir = salt['file.dirname'](manager.ssh.private_key_file) %}
+{%- set image_mine_data = salt['mine.get']('glance:client', 'glanceng.get_image_owner_id', 'pillar').values() %}
+{%- set network_mine_data = salt['mine.get']('neutron:client', 'list_octavia_networks', 'pillar').values() %}
+{%- set secgroup_mine_data = salt['mine.get']('neutron:client', 'list_octavia_mgmt_security_groups', 'pillar').values() %}
+
+{%- if image_mine_data and network_mine_data and secgroup_mine_data %}
+/etc/octavia/octavia_manager.conf:
+  file.managed:
+  - source: salt://octavia/files/{{ manager.version }}/octavia_manager.conf
+  - template: jinja
+  - context:
+    amp_image_owner_id: {{ image_mine_data|first }}
+    amp_boot_network_list: {{ (network_mine_data|first)['networks'][0]['id'] }}
+    amp_secgroup_list: {{ (secgroup_mine_data|first)['lb-mgmt-sec-grp']['id'] }}
+{%- endif %}
+
+{% set dhclient_conf_path = '/etc/octavia/dhcp/dhclient.conf' %}
+
+{{ dhclient_conf_path }}:
+  file.managed:
+  - source: salt://octavia/files/{{ manager.version }}/dhcp/dhclient.conf
+
+{%- endif %}
diff --git a/octavia/upgrade/service_running.sls b/octavia/upgrade/service_running.sls
new file mode 100644
index 0000000..ad37e12
--- /dev/null
+++ b/octavia/upgrade/service_running.sls
@@ -0,0 +1,21 @@
+{%- from "octavia/map.jinja" import api,manager with context %}
+
+octavia_service_running:
+  test.show_notification:
+    - text: "Running octavia.upgrade.service_running"
+
+{%- set oservices = [] %}
+
+{%- if api.enabled %}
+  {%- do oservices.extend(api.services) %}
+{%- endif %}
+{%- if manager.enabled %}
+  {%- do oservices.extend(manager.services) %}
+{%- endif %}
+
+{%- for oservice in oservices|unique %}
+octavia_service_{{ oservice }}_running:
+  service.running:
+  - enable: True
+  - name: {{ oservice }}
+{%- endfor %}
diff --git a/octavia/upgrade/service_stopped.sls b/octavia/upgrade/service_stopped.sls
new file mode 100644
index 0000000..df6fa85
--- /dev/null
+++ b/octavia/upgrade/service_stopped.sls
@@ -0,0 +1,21 @@
+{%- from "octavia/map.jinja" import api,manager with context %}
+
+octavia_service_stopped:
+  test.show_notification:
+    - text: "Running octavia.upgrade.service_stopped"
+
+{%- set oservices = [] %}
+
+{%- if api.enabled %}
+  {%- do oservices.extend(api.services) %}
+{%- endif %}
+{%- if manager.enabled %}
+  {%- do oservices.extend(manager.services) %}
+{%- endif %}
+
+{%- for oservice in oservices|unique %}
+octavia_service_{{ oservice }}_stopped:
+  service.dead:
+  - enable: True
+  - name: {{ oservice }}
+{%- endfor %}
diff --git a/octavia/upgrade/upgrade/init.sls b/octavia/upgrade/upgrade/init.sls
new file mode 100644
index 0000000..4666375
--- /dev/null
+++ b/octavia/upgrade/upgrade/init.sls
@@ -0,0 +1,8 @@
+include:
+ - octavia.upgrade.upgrade.pre
+ - octavia.upgrade.service_stopped
+ - octavia.upgrade.pkgs_latest
+ - octavia.upgrade.render_config
+ - octavia.db.offline_sync
+ - octavia.upgrade.service_running
+ - octavia.upgrade.upgrade.post
diff --git a/octavia/upgrade/upgrade/post.sls b/octavia/upgrade/upgrade/post.sls
new file mode 100644
index 0000000..664edf6
--- /dev/null
+++ b/octavia/upgrade/upgrade/post.sls
@@ -0,0 +1,3 @@
+octavia_upgrade_uprade_post:
+  test.show_notification:
+    - text: "Running octavia.upgrade.upgrade.post"
diff --git a/octavia/upgrade/upgrade/pre.sls b/octavia/upgrade/upgrade/pre.sls
new file mode 100644
index 0000000..dffa29f
--- /dev/null
+++ b/octavia/upgrade/upgrade/pre.sls
@@ -0,0 +1,3 @@
+octavia_upgrade_upgrade_pre:
+  test.show_notification:
+    - text: "Running octavia.upgrade.upgrade.pre"
\ No newline at end of file
diff --git a/octavia/upgrade/verify/_api.sls b/octavia/upgrade/verify/_api.sls
new file mode 100644
index 0000000..e308a64
--- /dev/null
+++ b/octavia/upgrade/verify/_api.sls
@@ -0,0 +1,3 @@
+octavia_upgrade_verify_api:
+  test.show_notification:
+    - text: "Running octavia.upgrade.verify.api"
\ No newline at end of file
diff --git a/octavia/upgrade/verify/init.sls b/octavia/upgrade/verify/init.sls
new file mode 100644
index 0000000..4b9358b
--- /dev/null
+++ b/octavia/upgrade/verify/init.sls
@@ -0,0 +1,2 @@
+include:
+ - octavia.upgrade.verify._api
\ No newline at end of file