Merge "[packaging] Switch using 3.0 native source format"
diff --git a/README.rst b/README.rst
index bc98bf2..a171ab2 100644
--- a/README.rst
+++ b/README.rst
@@ -811,6 +811,40 @@
 #. Apply the :command:`keystone.client` state.
 
 
+Fernet-keys rotation without gluster
+------------------------------------
+
+In the future fernet keys supposed to be rotated with rsync+ssh instead of using glusterfs. By default it is assumed
+that the script will run on primary control node (ctl01) and will rotate and transfer fernet keys to secondary
+controller nodes (ctl02, ctl03). Following parameter should be set on cluster level:
+
+keystone_node_role
+
+and fernet_rotation_driver should be set to 'rsync'
+
+By default this parameter is set to "secondary" on system level along with other parameters:
+.. code-block:: yaml
+
+  keystone:
+    server:
+      role: ${_param:keystone_node_role}
+    tokens:
+      fernet_sync_nodes_list:
+        control02:
+          name: ctl02
+          enabled: True
+        control03:
+          name: ctl03
+          enabled: True
+      fernet_rotation_driver: rsync
+
+Prior to running keystone salt states ssh key should be generated and its public part should be placed on secondary controllers.
+It can be accomplished by running following orchestration state before keystone states:
+
+salt-run state.orchestrate keystone.orchestrate.deploy
+
+Currently the default fernet rotation driver is a shared filesystem
+
 Documentation and Bugs
 ======================
 
diff --git a/keystone/files/fernet_keys_rotate.sh b/keystone/files/fernet_keys_rotate.sh
new file mode 100644
index 0000000..636e315
--- /dev/null
+++ b/keystone/files/fernet_keys_rotate.sh
@@ -0,0 +1,100 @@
+{%- from "keystone/map.jinja" import server with context -%}
+#!/bin/bash
+usage() {
+cat <<EOF
+Script for Fernet key rotation and sync
+    For additional help please use: $0 -h or --help
+    example: $0 -s
+EOF
+}
+
+if [ $# -lt "1" ]; then
+        usage
+        exit 1
+fi
+
+help_usage() {
+cat <<EOF
+Following options are supported:
+    -s  Perform sync to secondary controller nodes only
+    -r  Perform Fernet key rotation on primary controller only
+    -rs  Perform Fernet key rotation on primary controller and sync to secondary controller nodes
+EOF
+}
+
+if [ $# -lt "1" ]; then
+        usage
+        exit 1
+fi
+
+POSITIONAL=()
+while [[ $# -gt 0 ]]
+do
+key="$1"
+
+case $key in
+    -h|--help)
+    help_usage
+    shift # past argument
+    ;;
+    -s)
+    MODE="SYNC"
+    shift # past argument
+    ;;
+    -r)
+    MODE="ROTATE"
+    shift
+    ;;
+    -rs)
+    MODE="ROTATE_AND_SYNC"
+    shift
+    ;;
+    *)    # unknown option
+    echo "Unknown option. Please refer to help section by passing -h or --help option"
+    shift # past argument
+    ;;
+esac
+done
+set -- "${POSITIONAL[@]}" # restore positional parameters
+
+#Setting variables
+KEYSTONE_MANAGE_CMD="/usr/bin/keystone-manage"
+{%- if server.tokens.fernet_sync_nodes_list is defined %}
+        {%- set _nodes = [] %}
+          {%- for node_name, fernet_sync_nodes_list in server.tokens.get('fernet_sync_nodes_list', {}).iteritems() %}
+            {%- if fernet_sync_nodes_list.get('enabled', False) %}
+              {%- do _nodes.append(fernet_sync_nodes_list.name) %}
+            {%- endif %}
+          {%- endfor %}
+NODES="{{ ' '.join(_nodes) }}"
+{%- else %}
+NODES=""
+{%- endif %}
+
+if [[ ${MODE} == 'SYNC' ]]; then
+  echo "Running in SYNC mode"
+    if [[ ${NODES} != '' ]]; then
+      for NODE in ${NODES}; do
+        echo "${NODE}"
+        rsync -e 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' -avz --delete {{ server.tokens.location }}/ keystone@${NODE}:{{ server.tokens.location }}/
+      done
+    else
+      echo "List of nodes is not specified, no need for sync, exiting"
+      exit 0
+    fi
+elif [[ ${MODE} == 'ROTATE' ]]; then
+  echo "Running in ROTATE mode"
+  /usr/bin/keystone-manage --log-file /var/log/keystone/keystone-rotate.log fernet_rotate  --keystone-user keystone --keystone-group keystone
+elif [[ ${MODE} == 'ROTATE_AND_SYNC' ]]; then
+  echo "Running in ROTATE_AND_SYNC mode"
+  /usr/bin/keystone-manage --log-file /var/log/keystone/keystone-rotate.log fernet_rotate  --keystone-user keystone --keystone-group keystone
+  if [[ ${NODES} != '' ]]; then
+    for NODE in ${NODES}; do
+      echo "${NODE}"
+      rsync -e 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' -avz --delete {{ server.tokens.location }}/ keystone@${NODE}:{{ server.tokens.location }}/
+    done
+  else
+    echo "List of nodes is not specified, no need for sync, exiting"
+    exit 0
+  fi
+fi
diff --git a/keystone/meta/salt.yml b/keystone/meta/salt.yml
index 92324e5..554ed23 100644
--- a/keystone/meta/salt.yml
+++ b/keystone/meta/salt.yml
@@ -7,6 +7,12 @@
   control:
     priority: 520
 
+orchestration:
+  deploy:
+    applications:
+      keystone:
+        priority: 1000
+
 minion:
   {%- if pillar.get('keystone', {}).get('server') or pillar.get('keystone', {}).get('client') %}
     {%- from "keystone/map.jinja" import server with context %}
diff --git a/keystone/orchestrate/deploy.sls b/keystone/orchestrate/deploy.sls
new file mode 100644
index 0000000..eccbbab
--- /dev/null
+++ b/keystone/orchestrate/deploy.sls
@@ -0,0 +1,36 @@
+{%- set minions = ((salt['cmd.shell']("salt '*' match.pillar 'keystone:server:role:primary' --out=json --static"))|load_json).values() %}
+keystone_ssh_keys:
+  salt.state:
+    - tgt: 'I@keystone:server:role:primary'
+    - tgt_type: compound
+    - sls: keystone.orchestrate.generate_keystone_ssh_keys
+    - onlyif: {% if True in minions %}/bin/true{% else %}/bin/false{% endif %}
+
+send_keystone_public_key:
+  salt.state:
+    - tgt: 'I@keystone:server:role:primary'
+    - tgt_type: compound
+    - sls: keystone.orchestrate.send_keystone_public_key
+    - require:
+      - salt: keystone_ssh_keys
+    - onlyif: {% if True in minions %}/bin/true{% else %}/bin/false{% endif %}
+
+{%- set minions = ((salt['cmd.shell']("salt '*' match.pillar 'keystone:server' --out=json --static"))|load_json).values() %}
+salt_mine_update:
+  salt.state:
+    - tgt: 'I@keystone:server'
+    - tgt_type: compound
+    - sls: keystone.orchestrate.run_mine_update
+    - require:
+      - salt: send_keystone_public_key
+    - onlyif: {% if True in minions %}/bin/true{% else %}/bin/false{% endif %}
+
+{%- set minions = ((salt['cmd.shell']("salt '*' match.pillar 'keystone:server:role:secondary' --out=json --static"))|load_json).values() %}
+get_keystone_public_key:
+  salt.state:
+    - tgt: 'I@keystone:server:role:secondary'
+    - tgt_type: compound
+    - sls: keystone.orchestrate.get_keystone_public_key
+    - require:
+      - salt: salt_mine_update
+    - onlyif: {% if True in minions %}/bin/true{% else %}/bin/false{% endif %}
diff --git a/keystone/orchestrate/generate_keystone_ssh_keys.sls b/keystone/orchestrate/generate_keystone_ssh_keys.sls
new file mode 100644
index 0000000..c5f7ccb
--- /dev/null
+++ b/keystone/orchestrate/generate_keystone_ssh_keys.sls
@@ -0,0 +1,19 @@
+{%- from "keystone/map.jinja" import server with context %}
+applying_generate_keystone_ssh_keys_state:
+  test.succeed_without_changes
+{% if server.tokens.get('fernet_rotation_driver', 'shared_filesystem') == 'rsync' %}
+keystone_fernet_keys:
+  file.directory:
+  - name: {{ server.tokens.location }}
+  - mode: 750
+  - user: keystone
+  - group: keystone
+
+generate_keystone_ssh_keys:
+  cmd.run:
+    - name: ssh-keygen -q -N '' -f /var/lib/keystone/.ssh/id_rsa
+    - runas: keystone
+    - creates: /var/lib/keystone/.ssh/id_rsa
+    - require:
+      - file: {{ server.tokens.location }}
+{%- endif %}
diff --git a/keystone/orchestrate/get_keystone_public_key.sls b/keystone/orchestrate/get_keystone_public_key.sls
new file mode 100644
index 0000000..2be74e1
--- /dev/null
+++ b/keystone/orchestrate/get_keystone_public_key.sls
@@ -0,0 +1,37 @@
+{%- from "keystone/map.jinja" import server with context %}
+applying_get_keystone_public_key_state:
+  test.succeed_without_changes
+{% if server.tokens.get('fernet_rotation_driver', 'shared_filesystem') == 'rsync' %}
+{%- set authorized_keys = salt['mine.get']('I@keystone:server:role:primary', 'keystone_public_key', 'compound') %}
+
+keystone_fernet_keys:
+  file.directory:
+  - name: {{ server.tokens.location }}
+  - mode: 650
+  - user: keystone
+  - group: keystone
+
+/var/lib/keystone/.ssh:
+  file.directory:
+    - user: keystone
+    - group: keystone
+    - file_mode: 600
+    - dir_mode: 600
+    - makedirs: True
+    - recurse:
+      - user
+      - group
+      - mode
+
+  {% if authorized_keys is defined and authorized_keys|length > 0 %}
+put_keystone_file:
+  file.managed:
+    - name: /var/lib/keystone/.ssh/authorized_keys
+    - contents: '{{ authorized_keys.values()[0] }}'
+    - user: keystone
+    - group: keystone
+    - mode: 600
+    - require:
+      - file: /var/lib/keystone/.ssh
+  {%- endif %}
+{%- endif %}
diff --git a/keystone/orchestrate/run_mine_update.sls b/keystone/orchestrate/run_mine_update.sls
new file mode 100644
index 0000000..33e626c
--- /dev/null
+++ b/keystone/orchestrate/run_mine_update.sls
@@ -0,0 +1,8 @@
+{%- from "keystone/map.jinja" import server with context %}
+applying_run_mine_update_state:
+  test.succeed_without_changes
+{% if server.tokens.get('fernet_rotation_driver', 'shared_filesystem') == 'rsync' %}
+execute_mine_update:
+  module.run:
+    - name: mine.update
+{%- endif %}
diff --git a/keystone/orchestrate/send_keystone_public_key.sls b/keystone/orchestrate/send_keystone_public_key.sls
new file mode 100644
index 0000000..7edaf14
--- /dev/null
+++ b/keystone/orchestrate/send_keystone_public_key.sls
@@ -0,0 +1,13 @@
+{%- from "keystone/map.jinja" import server with context %}
+applying_send_keystone_public_key_state:
+  test.succeed_without_changes
+{% if server.tokens.get('fernet_rotation_driver', 'shared_filesystem') == 'rsync' %}
+mine_send_keystone_public_key:
+   module.run:
+    - name: mine.send
+    - func: keystone_public_key
+    - args:
+      - 'cat /var/lib/keystone/.ssh/id_rsa.pub'
+    - kwargs:
+       mine_function: cmd.run
+{%- endif %}
diff --git a/keystone/server.sls b/keystone/server.sls
index 9b43303..6e236c4 100644
--- a/keystone/server.sls
+++ b/keystone/server.sls
@@ -331,6 +331,31 @@
   - onlyif: /bin/false
     {%- endif %}
 
+  {% if server.tokens.get('fernet_rotation_driver', 'shared_filesystem') == 'rsync' %}
+    {% if server.get('role', 'secondary') == 'primary' %}
+/var/lib/keystone/fernet_keys_rotate.sh:
+  file.managed:
+  - source: salt://keystone/files/fernet_keys_rotate.sh
+  - template: jinja
+  - user: keystone
+  - group: keystone
+  - mode: 744
+  - require:
+    - pkg: keystone_packages
+    - file: keystone_fernet_keys
+    - cmd: keystone_fernet_setup
+
+run_fernet_rotation_script_in_sync_mode:
+  cmd.run:
+    - name: /var/lib/keystone/fernet_keys_rotate.sh -s
+    - runas: keystone
+    - require:
+      - pkg: keystone_packages
+      - file: /var/lib/keystone/fernet_keys_rotate.sh
+
+    {%- endif %}
+  {%- endif %}
+
 {% endif %}
 
 {%- if server.version in ['newton', 'ocata', 'pike'] %}