summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--heat_cfntools/cfntools/cfn_helper.py96
-rw-r--r--heat_cfntools/tests/test_cfn_helper.py211
2 files changed, 244 insertions, 63 deletions
diff --git a/heat_cfntools/cfntools/cfn_helper.py b/heat_cfntools/cfntools/cfn_helper.py
index 6d0aa48..6f7574b 100644
--- a/heat_cfntools/cfntools/cfn_helper.py
+++ b/heat_cfntools/cfntools/cfn_helper.py
@@ -22,7 +22,6 @@ import atexit
import ConfigParser
import errno
import grp
-import hashlib
import json
import logging
import os
@@ -714,37 +713,47 @@ class ServicesHandler(object):
self.hooks = hooks
def _handle_sysv_command(self, service, command):
- service_exe = "/sbin/service"
- enable_exe = "/sbin/chkconfig"
- cmd = ""
- if "enable" == command:
- cmd = "%s %s on" % (enable_exe, service)
- elif "disable" == command:
- cmd = "%s %s off" % (enable_exe, service)
- elif "start" == command:
- cmd = "%s %s start" % (service_exe, service)
- elif "stop" == command:
- cmd = "%s %s stop" % (service_exe, service)
- elif "status" == command:
- cmd = "%s %s status" % (service_exe, service)
- command = CommandRunner(cmd)
- command.run()
- return command
+ if os.path.exists("/bin/systemctl"):
+ service_exe = "/bin/systemctl"
+ service = '%s.service' % service
+ service_start = '%s start %s'
+ service_status = '%s status %s'
+ service_stop = '%s stop %s'
+ elif os.path.exists("/sbin/service"):
+ service_exe = "/sbin/service"
+ service_start = '%s %s start'
+ service_status = '%s %s status'
+ service_stop = '%s %s stop'
+ else:
+ service_exe = "/usr/sbin/service"
+ service_start = '%s %s start'
+ service_status = '%s %s status'
+ service_stop = '%s %s stop'
+
+ if os.path.exists("/bin/systemctl"):
+ enable_exe = "/bin/systemctl"
+ enable_on = '%s enable %s'
+ enable_off = '%s disable %s'
+ elif os.path.exists("/sbin/chkconfig"):
+ enable_exe = "/sbin/chkconfig"
+ enable_on = '%s %s on'
+ enable_off = '%s %s off'
+ else:
+ enable_exe = "/usr/sbin/update-rc.d"
+ enable_on = '%s %s enable'
+ enable_off = '%s %s disable'
- def _handle_systemd_command(self, service, command):
- exe = "/bin/systemctl"
cmd = ""
- service = '%s.service' % service
if "enable" == command:
- cmd = "%s enable %s" % (exe, service)
+ cmd = enable_on % (enable_exe, service)
elif "disable" == command:
- cmd = "%s disable %s" % (exe, service)
+ cmd = enable_off % (enable_exe, service)
elif "start" == command:
- cmd = "%s start %s" % (exe, service)
+ cmd = service_start % (service_exe, service)
elif "stop" == command:
- cmd = "%s stop %s" % (exe, service)
+ cmd = service_stop % (service_exe, service)
elif "status" == command:
- cmd = "%s status %s" % (exe, service)
+ cmd = service_status % (service_exe, service)
command = CommandRunner(cmd)
command.run()
return command
@@ -796,7 +805,7 @@ class ServicesHandler(object):
# map of function pointers to various service handlers
_service_handlers = {
"sysvinit": _handle_sysv_command,
- "systemd": _handle_systemd_command
+ "systemd": _handle_sysv_command
}
def _service_handler(self, manager_name):
@@ -1179,6 +1188,11 @@ class Metadata(object):
True -- success
False -- error
"""
+ if self.resource is not None:
+ res_last_path = last_path + '_' + self.resource
+ else:
+ res_last_path = last_path
+
if meta_str:
self._data = meta_str
else:
@@ -1198,7 +1212,7 @@ class Metadata(object):
# cached metadata or the logic below could re-run a stale
# cfn-init-data
fd = None
- for filepath in [last_path, default_path]:
+ for filepath in [res_last_path, last_path, default_path]:
try:
fd = open(filepath)
except IOError:
@@ -1221,18 +1235,21 @@ class Metadata(object):
else:
self._metadata = self._data
- cm = hashlib.md5(json.dumps(self._metadata))
- current_md5 = cm.hexdigest()
- old_md5 = None
+ last_data = ""
+ for metadata_file in [res_last_path, last_path]:
+ try:
+ with open(metadata_file) as lm:
+ try:
+ last_data = json.load(lm)
+ except ValueError:
+ pass
+ lm.close()
+ except IOError:
+ LOG.warn("Unable to open local metadata : %s" %
+ metadata_file)
+ continue
- try:
- with open(last_path) as lm:
- om = hashlib.md5()
- om.update(lm.read())
- old_md5 = om.hexdigest()
- except Exception:
- pass
- if old_md5 != current_md5:
+ if self._metadata != last_data:
self._has_changed = True
# if cache dir does not exist try to create it
@@ -1252,6 +1269,9 @@ class Metadata(object):
os.chmod(cf.name, 0o600)
cf.write(json.dumps(self._metadata))
os.rename(cf.name, last_path)
+ cf.close()
+ if res_last_path != last_path:
+ shutil.copy(last_path, res_last_path)
return True
diff --git a/heat_cfntools/tests/test_cfn_helper.py b/heat_cfntools/tests/test_cfn_helper.py
index bdda61f..49c7206 100644
--- a/heat_cfntools/tests/test_cfn_helper.py
+++ b/heat_cfntools/tests/test_cfn_helper.py
@@ -158,6 +158,8 @@ class TestPackages(MockPopenTestCase):
class TestServicesHandler(MockPopenTestCase):
def test_services_handler_systemd(self):
+ self.m.StubOutWithMock(os.path, 'exists')
+ os.path.exists('/bin/systemctl').MultipleTimes().AndReturn(True)
# apply_services
self.mock_cmd_run(
['su', 'root', '-c', '/bin/systemctl enable httpd.service']
@@ -234,6 +236,8 @@ class TestServicesHandler(MockPopenTestCase):
self.m.VerifyAll()
def test_services_handler_systemd_disabled(self):
+ self.m.StubOutWithMock(os.path, 'exists')
+ os.path.exists('/bin/systemctl').MultipleTimes().AndReturn(True)
# apply_services
self.mock_cmd_run(
['su', 'root', '-c', '/bin/systemctl disable httpd.service']
@@ -275,7 +279,11 @@ class TestServicesHandler(MockPopenTestCase):
self.m.VerifyAll()
- def test_services_handler_sysv(self):
+ def test_services_handler_sysv_service_chkconfig(self):
+ self.m.StubOutWithMock(os.path, 'exists')
+ os.path.exists('/bin/systemctl').MultipleTimes().AndReturn(False)
+ os.path.exists('/sbin/service').MultipleTimes().AndReturn(True)
+ os.path.exists('/sbin/chkconfig').MultipleTimes().AndReturn(True)
# apply_services
self.mock_cmd_run(
['su', 'root', '-c', '/sbin/chkconfig httpd on']
@@ -286,50 +294,118 @@ class TestServicesHandler(MockPopenTestCase):
self.mock_cmd_run(
['su', 'root', '-c', '/sbin/service httpd start']
).AndReturn(FakePOpen())
+
+ # monitor_services not running
+ self.mock_cmd_run(
+ ['su', 'root', '-c', '/sbin/service httpd status']
+ ).AndReturn(FakePOpen(returncode=-1))
self.mock_cmd_run(
- ['su', 'root', '-c', '/sbin/chkconfig mysqld on']
+ ['su', 'root', '-c', '/sbin/service httpd start']
).AndReturn(FakePOpen())
self.mock_cmd_run(
- ['su', 'root', '-c', '/sbin/service mysqld status']
- ).AndReturn(FakePOpen(returncode=-1))
+ ['su', 'root', '-c', '/bin/services_restarted']
+ ).AndReturn(FakePOpen())
+
+ # monitor_services running
self.mock_cmd_run(
- ['su', 'root', '-c', '/sbin/service mysqld start']
+ ['su', 'root', '-c', '/sbin/service httpd status']
).AndReturn(FakePOpen())
- # monitor_services not running
+ self.m.ReplayAll()
+
+ services = {
+ "sysvinit": {
+ "httpd": {"enabled": "true", "ensureRunning": "true"}
+ }
+ }
+ hooks = [
+ cfn_helper.Hook(
+ 'hook1',
+ 'service.restarted',
+ 'Resources.resource1.Metadata',
+ 'root',
+ '/bin/services_restarted')
+ ]
+ sh = cfn_helper.ServicesHandler(services, 'resource1', hooks)
+ sh.apply_services()
+ # services not running
+ sh.monitor_services()
+
+ # services running
+ sh.monitor_services()
+
+ self.m.VerifyAll()
+
+ def test_services_handler_sysv_disabled_service_chkconfig(self):
+ self.m.StubOutWithMock(os.path, 'exists')
+ os.path.exists('/bin/systemctl').MultipleTimes().AndReturn(False)
+ os.path.exists('/sbin/service').MultipleTimes().AndReturn(True)
+ os.path.exists('/sbin/chkconfig').MultipleTimes().AndReturn(True)
+ # apply_services
+ self.mock_cmd_run(
+ ['su', 'root', '-c', '/sbin/chkconfig httpd off']
+ ).AndReturn(FakePOpen())
self.mock_cmd_run(
['su', 'root', '-c', '/sbin/service httpd status']
- ).AndReturn(FakePOpen(returncode=-1))
+ ).AndReturn(FakePOpen())
self.mock_cmd_run(
- ['su', 'root', '-c', '/sbin/service httpd start']
+ ['su', 'root', '-c', '/sbin/service httpd stop']
).AndReturn(FakePOpen())
+
+ self.m.ReplayAll()
+
+ services = {
+ "sysvinit": {
+ "httpd": {"enabled": "false", "ensureRunning": "false"}
+ }
+ }
+ hooks = [
+ cfn_helper.Hook(
+ 'hook1',
+ 'service.restarted',
+ 'Resources.resource1.Metadata',
+ 'root',
+ '/bin/services_restarted')
+ ]
+ sh = cfn_helper.ServicesHandler(services, 'resource1', hooks)
+ sh.apply_services()
+
+ self.m.VerifyAll()
+
+ def test_services_handler_sysv_systemctl(self):
+ self.m.StubOutWithMock(os.path, 'exists')
+ os.path.exists('/bin/systemctl').MultipleTimes().AndReturn(True)
+ # apply_services
self.mock_cmd_run(
- ['su', 'root', '-c', '/bin/services_restarted']
+ ['su', 'root', '-c', '/bin/systemctl enable httpd.service']
).AndReturn(FakePOpen())
self.mock_cmd_run(
- ['su', 'root', '-c', '/sbin/service mysqld status']
+ ['su', 'root', '-c', '/bin/systemctl status httpd.service']
).AndReturn(FakePOpen(returncode=-1))
self.mock_cmd_run(
- ['su', 'root', '-c', '/sbin/service mysqld start']
+ ['su', 'root', '-c', '/bin/systemctl start httpd.service']
).AndReturn(FakePOpen())
+
+ # monitor_services not running
self.mock_cmd_run(
- ['su', 'root', '-c', '/bin/services_restarted']
+ ['su', 'root', '-c', '/bin/systemctl status httpd.service']
+ ).AndReturn(FakePOpen(returncode=-1))
+ self.mock_cmd_run(
+ ['su', 'root', '-c', '/bin/systemctl start httpd.service']
).AndReturn(FakePOpen())
-
- # monitor_services running
self.mock_cmd_run(
- ['su', 'root', '-c', '/sbin/service httpd status']
+ ['su', 'root', '-c', '/bin/services_restarted']
).AndReturn(FakePOpen())
+ # monitor_services running
self.mock_cmd_run(
- ['su', 'root', '-c', '/sbin/service mysqld status']
+ ['su', 'root', '-c', '/bin/systemctl status httpd.service']
).AndReturn(FakePOpen())
self.m.ReplayAll()
services = {
"sysvinit": {
- "mysqld": {"enabled": "true", "ensureRunning": "true"},
"httpd": {"enabled": "true", "ensureRunning": "true"}
}
}
@@ -351,32 +427,117 @@ class TestServicesHandler(MockPopenTestCase):
self.m.VerifyAll()
- def test_services_handler_sysv_disabled(self):
+ def test_services_handler_sysv_disabled_systemctl(self):
+ self.m.StubOutWithMock(os.path, 'exists')
+ os.path.exists('/bin/systemctl').MultipleTimes().AndReturn(True)
# apply_services
self.mock_cmd_run(
- ['su', 'root', '-c', '/sbin/chkconfig httpd off']
+ ['su', 'root', '-c', '/bin/systemctl disable httpd.service']
).AndReturn(FakePOpen())
self.mock_cmd_run(
- ['su', 'root', '-c', '/sbin/service httpd status']
+ ['su', 'root', '-c', '/bin/systemctl status httpd.service']
).AndReturn(FakePOpen())
self.mock_cmd_run(
- ['su', 'root', '-c', '/sbin/service httpd stop']
+ ['su', 'root', '-c', '/bin/systemctl stop httpd.service']
+ ).AndReturn(FakePOpen())
+
+ self.m.ReplayAll()
+
+ services = {
+ "sysvinit": {
+ "httpd": {"enabled": "false", "ensureRunning": "false"}
+ }
+ }
+ hooks = [
+ cfn_helper.Hook(
+ 'hook1',
+ 'service.restarted',
+ 'Resources.resource1.Metadata',
+ 'root',
+ '/bin/services_restarted')
+ ]
+ sh = cfn_helper.ServicesHandler(services, 'resource1', hooks)
+ sh.apply_services()
+
+ self.m.VerifyAll()
+
+ def test_services_handler_sysv_service_updaterc(self):
+ self.m.StubOutWithMock(os.path, 'exists')
+ os.path.exists('/bin/systemctl').MultipleTimes().AndReturn(False)
+ os.path.exists('/sbin/service').MultipleTimes().AndReturn(False)
+ os.path.exists('/sbin/chkconfig').MultipleTimes().AndReturn(False)
+ # apply_services
+ self.mock_cmd_run(
+ ['su', 'root', '-c', '/usr/sbin/update-rc.d httpd enable']
+ ).AndReturn(FakePOpen())
+ self.mock_cmd_run(
+ ['su', 'root', '-c', '/usr/sbin/service httpd status']
+ ).AndReturn(FakePOpen(returncode=-1))
+ self.mock_cmd_run(
+ ['su', 'root', '-c', '/usr/sbin/service httpd start']
+ ).AndReturn(FakePOpen())
+
+ # monitor_services not running
+ self.mock_cmd_run(
+ ['su', 'root', '-c', '/usr/sbin/service httpd status']
+ ).AndReturn(FakePOpen(returncode=-1))
+ self.mock_cmd_run(
+ ['su', 'root', '-c', '/usr/sbin/service httpd start']
+ ).AndReturn(FakePOpen())
+ self.mock_cmd_run(
+ ['su', 'root', '-c', '/bin/services_restarted']
+ ).AndReturn(FakePOpen())
+
+ # monitor_services running
+ self.mock_cmd_run(
+ ['su', 'root', '-c', '/usr/sbin/service httpd status']
).AndReturn(FakePOpen())
+
+ self.m.ReplayAll()
+
+ services = {
+ "sysvinit": {
+ "httpd": {"enabled": "true", "ensureRunning": "true"}
+ }
+ }
+ hooks = [
+ cfn_helper.Hook(
+ 'hook1',
+ 'service.restarted',
+ 'Resources.resource1.Metadata',
+ 'root',
+ '/bin/services_restarted')
+ ]
+ sh = cfn_helper.ServicesHandler(services, 'resource1', hooks)
+ sh.apply_services()
+ # services not running
+ sh.monitor_services()
+
+ # services running
+ sh.monitor_services()
+
+ self.m.VerifyAll()
+
+ def test_services_handler_sysv_disabled_service_updaterc(self):
+ self.m.StubOutWithMock(os.path, 'exists')
+ os.path.exists('/bin/systemctl').MultipleTimes().AndReturn(False)
+ os.path.exists('/sbin/service').MultipleTimes().AndReturn(False)
+ os.path.exists('/sbin/chkconfig').MultipleTimes().AndReturn(False)
+ # apply_services
self.mock_cmd_run(
- ['su', 'root', '-c', '/sbin/chkconfig mysqld off']
+ ['su', 'root', '-c', '/usr/sbin/update-rc.d httpd disable']
).AndReturn(FakePOpen())
self.mock_cmd_run(
- ['su', 'root', '-c', '/sbin/service mysqld status']
+ ['su', 'root', '-c', '/usr/sbin/service httpd status']
).AndReturn(FakePOpen())
self.mock_cmd_run(
- ['su', 'root', '-c', '/sbin/service mysqld stop']
+ ['su', 'root', '-c', '/usr/sbin/service httpd stop']
).AndReturn(FakePOpen())
self.m.ReplayAll()
services = {
"sysvinit": {
- "mysqld": {"enabled": "false", "ensureRunning": "false"},
"httpd": {"enabled": "false", "ensureRunning": "false"}
}
}