Merge lp:~verterok/charms/trusty/tanuki-spec-manager/sane_db-relation-changed_restarts into lp:~tanuki/charms/trusty/tanuki-spec-manager/trunk

Proposed by Guillermo Gonzalez
Status: Merged
Approved by: Guillermo Gonzalez
Approved revision: 39
Merged at revision: 34
Proposed branch: lp:~verterok/charms/trusty/tanuki-spec-manager/sane_db-relation-changed_restarts
Merge into: lp:~tanuki/charms/trusty/tanuki-spec-manager/trunk
Diff against target: 150 lines (+69/-30)
2 files modified
hooks/actions.py (+68/-27)
hooks/services.py (+1/-3)
To merge this branch: bzr merge lp:~verterok/charms/trusty/tanuki-spec-manager/sane_db-relation-changed_restarts
Reviewer Review Type Date Requested Status
Celso Providelo (community) Approve
Review via email: mp+276530@code.launchpad.net

Commit message

Fix handling of db-relation-changed hook and avoid pointless restarts.

Description of the change

"reuse" some knowledge from landscape charm on how handle db-relation-changed hook and avoid pointless restarts.

This is to fix the case of adding a new service/unit relation to postgresql and getting a db-relation-changed triggered on all already related services, with a change on allowed-units field which shouldn't trigger a restart on all other services.

To post a comment you must log in.
Revision history for this message
Celso Providelo (cprov) wrote :

Thanks, Guillo.

I am happy to try it on staging and if it works fine propagate the Restart(ManagerCallback) to other charms, since it's very portable.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'hooks/actions.py'
--- hooks/actions.py 2015-10-29 21:27:35 +0000
+++ hooks/actions.py 2015-11-03 23:08:19 +0000
@@ -5,13 +5,15 @@
5import subprocess5import subprocess
6import yaml6import yaml
77
8from hashlib import md5
9
8from charmhelpers import fetch10from charmhelpers import fetch
9from charmhelpers.core import (11from charmhelpers.core import (
10 hookenv,12 hookenv,
11 host,13 host,
12)14)
13from charmhelpers.core.services import helpers15from charmhelpers.core.services import helpers
14from charmhelpers.core.services.base import service_restart16from charmhelpers.core.services.base import service_restart, ManagerCallback
15from charmhelpers.core.templating import render17from charmhelpers.core.templating import render
16from charmhelpers.payload import (18from charmhelpers.payload import (
17 archive,19 archive,
@@ -36,31 +38,70 @@
36ETC_DIR = os.path.join(BASE_DIR, 'etc')38ETC_DIR = os.path.join(BASE_DIR, 'etc')
3739
3840
39def restart(service_name):41class Restart(ManagerCallback):
40 """Restart the service, only if the config changed"""42 """Restart the service, only if the config or relevant bits of the
41 current_config_hash = get_config_file_hash()43 db-relation changed
42 if current_config_hash != config['current_config_hash']:44 """
43 service_restart(service_name)45
4446 no_restart_db_keys = ('allowed-units',)
4547
46def get_config_file_hash():48 def _get_required_data(self, manager, service_name, key):
47 from hashlib import md549 """Get the service manager required_data entry matching the given key"""
48 config_file = os.path.join(SERVICE_DIR, 'service.conf')50 service = manager.get_service(service_name)
49 if not os.path.exists(config_file):51 for data in service["required_data"]:
50 return None52 if key in data:
51 with open(config_file, 'r') as fd:53 return data[key]
52 h = md5(fd.read())54
53 return h.hexdigest()55 def _update_persisted_data(self, key, value):
5456 """Persist the given 'value' for the given 'key' and return the old value.
5557
56def refresh_config_hash(service_name):58 @param key: The key to update.
57 current_config_hash = get_config_file_hash()59 @param value: The value to persist.
58 config['current_config_hash'] = current_config_hash60 @return: The old value of the key, or None if it's a new value.
59 config.save()61 """
6062 old = config.get(key, None)
6163 config[key] = value
62def log_start(service_name):64 config.save()
63 hookenv.log('spec-manager starting')65 return old
66
67 def _needs_restart_db_changed(self, db_new, db_old):
68 if db_old is None:
69 return True
70 new = db_new.copy()
71 old = db_old.copy()
72 for key in self.no_restart_db_keys:
73 new.pop(key)
74 old.pop(key, None)
75 return new != old
76
77 def get_config_file_hash(self):
78 config_file = os.path.join(SERVICE_DIR, 'service.conf')
79 if not os.path.exists(config_file):
80 return None
81 with open(config_file, 'r') as fd:
82 h = md5(fd.read())
83 return h.hexdigest()
84
85 def __call__(self, manager, service_name, event_name):
86
87 if hookenv.hook_name() == 'db-relation-changed':
88 db_new = self._get_required_data(manager, service_name, 'db')
89 # for some unknown reason we can get a list or dict
90 if isinstance(db_new, list):
91 db_new = db_new[0]
92 db_old = self._update_persisted_data('db', db_new)
93 if self._needs_restart_db_changed(db_new, db_old):
94 hookenv.log('Restarting service, db config changed')
95 service_restart(service_name)
96 return
97 elif hookenv.hook_name() == 'config-changed':
98 config_new = self.get_config_file_hash()
99 config_old = self._update_persisted_data('config_hash', config_new)
100 if config_new != config_old:
101 hookenv.log('Restarting service, config file changed')
102 service_restart(service_name)
103 return
104 hookenv.log('Not restarting service, config and db-relation unchanged')
64105
65106
66def ensure_directories(service_name):107def ensure_directories(service_name):
@@ -323,7 +364,7 @@
323 username=parsed.username,364 username=parsed.username,
324 password=parsed.password,365 password=parsed.password,
325 use_tls=use_tls,366 use_tls=use_tls,
326 vhost=vhost)367 vhost=vhost)
327 checks.append(amqp_check)368 checks.append(amqp_check)
328 return checks369 return checks
329370
330371
=== modified file 'hooks/services.py'
--- hooks/services.py 2015-10-29 21:27:35 +0000
+++ hooks/services.py 2015-11-03 23:08:19 +0000
@@ -18,7 +18,6 @@
18 'required_data': [config,18 'required_data': [config,
19 actions.PostgresqlRelation(required=True)],19 actions.PostgresqlRelation(required=True)],
20 'data_ready': [20 'data_ready': [
21 actions.refresh_config_hash,
22 actions.ensure_directories,21 actions.ensure_directories,
23 actions.get_cloud_service_from_tarball,22 actions.get_cloud_service_from_tarball,
24 actions.install_python_packages,23 actions.install_python_packages,
@@ -30,11 +29,10 @@
30 actions.write_db_config,29 actions.write_db_config,
31 actions.setup_store_poller,30 actions.setup_store_poller,
32 actions.publish_conn_check_relation_data,31 actions.publish_conn_check_relation_data,
33 actions.log_start,
34 actions.nrpe_external_master_relation,32 actions.nrpe_external_master_relation,
35 ],33 ],
36 'start': [34 'start': [
37 actions.restart35 actions.Restart()
38 ],36 ],
39 },37 },
40 ])38 ])

Subscribers

People subscribed via source and target branches