blob: b014f49c2b40d2d697044fb843002090e3efbd18 [file] [log] [blame]
tyagi2cbc0a82015-05-21 02:53:14 -07001# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12
Oleksii Chuprykov4be023a2015-07-08 07:17:08 -040013import time
14
tyagi2cbc0a82015-05-21 02:53:14 -070015import eventlet
16
17from oslo_concurrency import processutils
18from six.moves import configparser
19
Rabi Mishra477efc92015-07-31 13:01:45 +053020from heat_integrationtests.functional import functional_base
tyagi2cbc0a82015-05-21 02:53:14 -070021
22
Rabi Mishra477efc92015-07-31 13:01:45 +053023class ReloadOnSighupTest(functional_base.FunctionalTestsBase):
tyagi2cbc0a82015-05-21 02:53:14 -070024
25 def setUp(self):
26 self.config_file = "/etc/heat/heat.conf"
27 super(ReloadOnSighupTest, self).setUp()
28
29 def _set_config_value(self, service, key, value):
30 config = configparser.ConfigParser()
Peter Razumovsky483e64b2016-03-04 17:04:28 +030031
32 # NOTE(prazumovsky): If there are several workers, there can be
33 # situation, when one thread opens self.config_file for writing
34 # (so config_file erases with opening), in that moment other thread
35 # intercepts to this file and try to set config option value, i.e.
36 # write to file, which is already erased by first thread, so,
37 # NoSectionError raised. So, should wait until first thread writes to
38 # config_file.
39 retries_count = self.conf.sighup_config_edit_retries
40 while True:
41 config.read(self.config_file)
42 try:
43 config.set(service, key, value)
44 except configparser.NoSectionError:
45 if retries_count <= 0:
46 raise
47 retries_count -= 1
48 eventlet.sleep(1)
49 else:
50 break
51
tyagi2cbc0a82015-05-21 02:53:14 -070052 with open(self.config_file, 'wb') as f:
53 config.write(f)
54
55 def _get_config_value(self, service, key):
56 config = configparser.ConfigParser()
57 config.read(self.config_file)
58 val = config.get(service, key)
59 return val
60
61 def _get_heat_api_pids(self, service):
62 # get the pids of all heat-api processes
63 if service == "heat_api":
64 process = "heat-api|grep -Ev 'grep|cloudwatch|cfn'"
65 else:
66 process = "%s|grep -Ev 'grep'" % service.replace('_', '-')
67 cmd = "ps -ef|grep %s|awk '{print $2}'" % process
68 out, err = processutils.execute(cmd, shell=True)
69 self.assertIsNotNone(out, "heat-api service not running. %s" % err)
70 pids = filter(None, out.split('\n'))
71
72 # get the parent pids of all heat-api processes
73 cmd = "ps -ef|grep %s|awk '{print $3}'" % process
74 out, _ = processutils.execute(cmd, shell=True)
75 parent_pids = filter(None, out.split('\n'))
76
77 heat_api_parent = list(set(pids) & set(parent_pids))[0]
78 heat_api_children = list(set(pids) - set(parent_pids))
79
80 return heat_api_parent, heat_api_children
81
82 def _change_config(self, service, old_workers, new_workers):
83 pre_reload_parent, pre_reload_children = self._get_heat_api_pids(
84 service)
85 self.assertEqual(old_workers, len(pre_reload_children))
86
87 # change the config values
88 self._set_config_value(service, 'workers', new_workers)
89 cmd = "kill -HUP %s" % pre_reload_parent
90 processutils.execute(cmd, shell=True)
tyagi2cbc0a82015-05-21 02:53:14 -070091
Oleksii Chuprykov4be023a2015-07-08 07:17:08 -040092 # wait till heat-api reloads
93 start_time = time.time()
94 while time.time() - start_time < self.conf.sighup_timeout:
95 post_reload_parent, post_reload_children = self._get_heat_api_pids(
96 service)
97 intersect = set(post_reload_children) & set(pre_reload_children)
98 if (new_workers == len(post_reload_children)
99 and pre_reload_parent == post_reload_parent
100 and intersect == set()):
101 break
102 eventlet.sleep(1)
tyagi2cbc0a82015-05-21 02:53:14 -0700103 self.assertEqual(pre_reload_parent, post_reload_parent)
104 self.assertEqual(new_workers, len(post_reload_children))
105 # test if all child processes are newly created
106 self.assertEqual(set(post_reload_children) & set(pre_reload_children),
107 set())
108
109 def _reload(self, service):
110 old_workers = int(self._get_config_value(service, 'workers'))
111 new_workers = old_workers + 1
112 self.addCleanup(self._set_config_value, service, 'workers',
113 old_workers)
114
115 self._change_config(service, old_workers, new_workers)
116 # revert all the changes made
117 self._change_config(service, new_workers, old_workers)
118
119 def test_api_reload_on_sighup(self):
120 self._reload('heat_api')
121
122 def test_api_cfn_reload_on_sighup(self):
123 self._reload('heat_api_cfn')
124
125 def test_api_cloudwatch_on_sighup(self):
126 self._reload('heat_api_cloudwatch')