From 72ac7a5541e510cadfec0dc6754c5cf52503b187 Mon Sep 17 00:00:00 2001
From: Jeffrey Zhang <jeffrey.zhang@99cloud.net>
Date: Thu, 25 Feb 2016 08:19:35 +0800
Subject: [PATCH] Reconfigure keystone service

Partially-implements: bp kolla-reconfig

Change-Id: Ied293e59bf4531e88a0e5e5bf9a5f5f495d2a0e7
---
 .../roles/keystone/tasks/do_reconfigure.yml   | 39 ++++++++++++++
 ansible/roles/keystone/tasks/reconfigure.yml  |  2 +
 docker/base/set_configs.py                    | 53 +++++++++++++++++--
 tests/test_set_config.py                      |  6 ++-
 4 files changed, 95 insertions(+), 5 deletions(-)
 create mode 100644 ansible/roles/keystone/tasks/do_reconfigure.yml

diff --git a/ansible/roles/keystone/tasks/do_reconfigure.yml b/ansible/roles/keystone/tasks/do_reconfigure.yml
new file mode 100644
index 0000000000..8974a35586
--- /dev/null
+++ b/ansible/roles/keystone/tasks/do_reconfigure.yml
@@ -0,0 +1,39 @@
+---
+- include: config.yml
+
+- name: Check the configs
+  command: docker exec keystone /usr/local/bin/kolla_set_configs --check
+  changed_when: false
+  failed_when: false
+  register: check_result
+
+# NOTE(jeffrey4l): when config_strategy == 'COPY_ALWAYS'
+# and container env['KOLLA_CONFIG_STRATEGY'] == 'COPY_ONCE',
+# just remove the container and start again
+- name: Container config strategy
+  command: docker exec keystone printenv KOLLA_CONFIG_STRATEGY
+  changed_when: false
+  failed_when: false
+  register: container_config_strategy
+
+- name: Remove the keystone container
+  kolla_docker:
+    name: "keystone"
+    action: "remove_container"
+  when:
+    - config_strategy == "COPY_ONCE" or container_config_strategy.stdout == 'COPY_ONCE'
+    - check_result.rc == 1
+
+- include: start.yml
+  when:
+    - config_strategy == "COPY_ONCE" or container_config_strategy.stdout == 'COPY_ONCE'
+    - check_result.rc == 1
+
+- name: Restart keystone service
+  # TODO(jeffrey4l): move to the kolla_docker module when
+  # it has restart_container action
+  command: docker restart keystone
+  when:
+    - config_strategy == 'COPY_ALWAYS'
+    - container_config_strategy.stdout != 'COPY_ONCE'
+    - check_result.rc == 1
diff --git a/ansible/roles/keystone/tasks/reconfigure.yml b/ansible/roles/keystone/tasks/reconfigure.yml
index ed97d539c0..66933249bb 100644
--- a/ansible/roles/keystone/tasks/reconfigure.yml
+++ b/ansible/roles/keystone/tasks/reconfigure.yml
@@ -1 +1,3 @@
 ---
+- include: do_reconfigure.yml
+  serial: "30%"
diff --git a/docker/base/set_configs.py b/docker/base/set_configs.py
index 8b94518af4..16e3c35eb0 100644
--- a/docker/base/set_configs.py
+++ b/docker/base/set_configs.py
@@ -12,6 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import argparse
 import contextlib
 import json
 import logging
@@ -235,7 +236,10 @@ def load_config():
 
     LOG.info('Validating config file')
     validate_config(config)
+    return config
 
+
+def copy_config(config):
     if 'config_files' in config:
         LOG.info('Copying service configuration files')
         for data in config['config_files']:
@@ -255,23 +259,66 @@ def load_config():
 def execute_config_strategy():
     config_strategy = os.environ.get("KOLLA_CONFIG_STRATEGY")
     LOG.info("Kolla config strategy set to: %s", config_strategy)
+    config = load_config()
 
     if config_strategy == "COPY_ALWAYS":
-        load_config()
+        copy_config(config)
     elif config_strategy == "COPY_ONCE":
         if os.path.exists('/configured'):
             LOG.info("The config strategy prevents copying new configs")
             sys.exit(0)
         else:
-            load_config()
+            copy_config(config)
             os.mknod('/configured')
     else:
         LOG.error('KOLLA_CONFIG_STRATEGY is not set properly')
         sys.exit(1)
 
 
+def execute_config_check():
+    config = load_config()
+    for config_file in config.get('config_files', {}):
+        source = config_file.get('source')
+        dest = config_file.get('dest')
+        perm = config_file.get('perm')
+        owner = config_file.get('owner')
+        if not os.path.exists(dest):
+            LOG.error('Dest file not exist: %s', dest)
+            sys.exit(1)
+        # check content
+        with open(source) as fp1, open(dest) as fp2:
+            if fp1.read() != fp2.read():
+                LOG.error('The content of source file(%s) and'
+                          ' dest file(%s) are not equal.', source, dest)
+                sys.exit(1)
+        # check perm
+        file_stat = os.stat(dest)
+        actual_perm = oct(file_stat.st_mode)[-4:]
+        if perm != actual_perm:
+            LOG.error('Dest file does not have expected perm: %s, actual: %s',
+                      perm, actual_perm)
+            sys.exit(1)
+        # check owner
+        actual_user = pwd.getpwuid(file_stat.st_uid)
+        if actual_user.pw_name != owner:
+            LOG.error('Dest file does not have expected user: %s, actual: %s ',
+                      owner, actual_user.pw_name)
+            sys.exit(1)
+    LOG.info('The config files are in the expected state')
+
+
 def main():
-    execute_config_strategy()
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--check',
+                        action='store_true',
+                        required=False,
+                        help='Check whether the configs changed')
+    conf = parser.parse_args()
+
+    if conf.check:
+        execute_config_check()
+    else:
+        execute_config_strategy()
     return 0
 
 
diff --git a/tests/test_set_config.py b/tests/test_set_config.py
index 43884bdb30..03975d1568 100644
--- a/tests/test_set_config.py
+++ b/tests/test_set_config.py
@@ -38,7 +38,8 @@ class LoadFromFile(base.BaseTestCase):
 
         mo = mock.mock_open(read_data=in_config)
         with mock.patch.object(set_configs, 'open', mo):
-            set_configs.load_config()
+            config = set_configs.load_config()
+            set_configs.copy_config(config)
             self.assertEqual([
                 mock.call('/var/lib/kolla/config_files/config.json'),
                 mock.call().__enter__(),
@@ -59,7 +60,8 @@ class LoadFromEnv(base.BaseTestCase):
         mo = mock.mock_open()
         with mock.patch.object(set_configs, 'open', mo):
             with mock.patch.dict('os.environ', {'KOLLA_CONFIG': in_config}):
-                set_configs.load_config()
+                config = set_configs.load_config()
+                set_configs.copy_config(config)
                 self.assertEqual([mock.call('/run_command', 'w+'),
                                   mock.call().__enter__(),
                                   mock.call().write(u'/bin/true'),