Merge lp:~hloeung/ubuntu-repository-cache/monitor-path-to-synchost into lp:ubuntu-repository-cache
- monitor-path-to-synchost
- Merge into layer-ubuntu-repository-cache
Status: | Merged |
---|---|
Approved by: | Haw Loeung |
Approved revision: | 378 |
Merged at revision: | 364 |
Proposed branch: | lp:~hloeung/ubuntu-repository-cache/monitor-path-to-synchost |
Merge into: | lp:ubuntu-repository-cache |
Diff against target: |
292 lines (+212/-1) 5 files modified
config.yaml (+5/-0) files/systemd/mtr-synchost.timer (+12/-0) reactive/ubuntu_repository_cache.py (+54/-0) templates/systemd/mtr-synchost.service (+15/-0) tests/unit/test_ubuntu_repository_cache.py (+126/-1) |
To merge this branch: | bzr merge lp:~hloeung/ubuntu-repository-cache/monitor-path-to-synchost |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Thomas Cuthbert (community) | Approve | ||
Canonical IS Reviewers | Pending | ||
Review via email: mp+427705@code.launchpad.net |
Commit message
Enable option to capture and monitor path to the sync host
This is useful for debugging reachability issues with specific vendor/
Description of the change
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote : | # |
- 367. By Haw Loeung
-
Fix errors 'Executable path is not absolute' and 'Service lacks both ExecStart= and ExecStop= setting.'
- 368. By Haw Loeung
-
Fixed the unit test too
- 369. By Haw Loeung
-
Bump interval to 5mins at first, we can reduce it further if needed
- 370. By Haw Loeung
-
Fixed to use tmpdir
Thomas Cuthbert (tcuthbert) wrote : | # |
looking good! can you update the commit message as to why this change is happening? rest of my comments are inline.
Haw Loeung (hloeung) : | # |
- 371. By Haw Loeung
-
Fixed based on review
- 372. By Haw Loeung
-
Allow disabling of monitoring of path to the sync-host
- 373. By Haw Loeung
-
Make it disabled by default
Haw Loeung (hloeung) wrote : | # |
Commit message updated.
- 374. By Haw Loeung
-
Fixed based on review
- 375. By Haw Loeung
-
We can't use DynamicUser as that's not supported in the systemd version shipped with Xenial
- 376. By Haw Loeung
-
Using one isn't enough to reveal some of the hops likely due to ICMP rate limiting
- 377. By Haw Loeung
-
Bump count / report cycles some more
Thomas Cuthbert (tcuthbert) wrote : | # |
LGTM +1 with a comment inline.
- 378. By Haw Loeung
-
7 looks like a good balance with enough to reach archive.u.c during testing from AWS.
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote : | # |
Change successfully merged at revision 364
Preview Diff
1 | === modified file 'config.yaml' |
2 | --- config.yaml 2022-07-25 00:51:24 +0000 |
3 | +++ config.yaml 2022-08-04 02:35:54 +0000 |
4 | @@ -198,6 +198,11 @@ |
5 | This endpoint will check both metadata served from local storage as well |
6 | as pool files via the locally running squid-deb-proxy service. |
7 | default: True |
8 | + enable_sync-host_monitoring: |
9 | + type: boolean |
10 | + description: | |
11 | + Enable periodic mtr outputs to configured sync-host |
12 | + default: False |
13 | leader_unit: |
14 | type: string |
15 | default: '' |
16 | |
17 | === added directory 'files/systemd' |
18 | === added file 'files/systemd/mtr-synchost.timer' |
19 | --- files/systemd/mtr-synchost.timer 1970-01-01 00:00:00 +0000 |
20 | +++ files/systemd/mtr-synchost.timer 2022-08-04 02:35:54 +0000 |
21 | @@ -0,0 +1,12 @@ |
22 | +[Unit] |
23 | +Description=Monitor path to sync host regularly |
24 | + |
25 | +[Timer] |
26 | +Unit=mtr-synchost.service |
27 | +OnActiveSec=5min |
28 | +OnUnitActiveSec=5min |
29 | +RemainAfterElapse=no |
30 | +Persistent=false |
31 | + |
32 | +[Install] |
33 | +WantedBy=timers.target |
34 | |
35 | === modified file 'reactive/ubuntu_repository_cache.py' |
36 | --- reactive/ubuntu_repository_cache.py 2022-08-01 01:24:02 +0000 |
37 | +++ reactive/ubuntu_repository_cache.py 2022-08-04 02:35:54 +0000 |
38 | @@ -10,6 +10,8 @@ |
39 | import shutil |
40 | import subprocess |
41 | |
42 | +import jinja2 |
43 | + |
44 | from charms import reactive |
45 | from charms.layer import status |
46 | from charmhelpers.core import hookenv, host, unitdata |
47 | @@ -146,6 +148,8 @@ |
48 | reactive.clear_flag('ubuntu-repository-cache.configured') |
49 | reactive.clear_flag('nagios-nrpe.configured') |
50 | |
51 | + reactive.set_flag('ubuntu-repository-cache.update-systemd-mtr-required') |
52 | + |
53 | |
54 | @reactive.hook('start') |
55 | def start(): |
56 | @@ -320,6 +324,50 @@ |
57 | update_website_relation_data() |
58 | |
59 | |
60 | +@reactive.when_any('config.changed.sync_host', 'config.changed.enable_sync-host_monitoring') |
61 | +def update_systemd_mtr_required(): |
62 | + reactive.set_flag('ubuntu-repository-cache.update-systemd-mtr-required') |
63 | + |
64 | + |
65 | +@reactive.when('ubuntu-repository-cache.update-systemd-mtr-required') |
66 | +def update_systemd_mtr(etc_systemd_path='/etc/systemd/system'): |
67 | + config = hookenv.config() |
68 | + reactive.clear_flag('ubuntu-repository-cache.active') |
69 | + |
70 | + mtr_service = os.path.join(etc_systemd_path, 'mtr-synchost.service') |
71 | + mtr_timer = os.path.join(etc_systemd_path, 'mtr-synchost.timer') |
72 | + |
73 | + if config['enable_sync-host_monitoring']: |
74 | + status.maintenance('Updating systemd mtr timer & service with sync-host {}'.format(config['sync-host'])) |
75 | + |
76 | + changed = False |
77 | + |
78 | + base = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) |
79 | + env = jinja2.Environment(loader=jinja2.FileSystemLoader(base), keep_trailing_newline=True) |
80 | + template = env.get_template('templates/systemd/mtr-synchost.service') |
81 | + contents = template.render({'sync_host': config['sync-host']}) |
82 | + changed = _write_file(contents, mtr_service) or changed |
83 | + changed = _copy_file('files/systemd/mtr-synchost.timer', mtr_timer) or changed |
84 | + |
85 | + if changed: |
86 | + status.maintenance('Calling systemctl daemon-reload') |
87 | + subprocess.call(['systemctl', 'daemon-reload']) |
88 | + subprocess.call(['systemctl', 'enable', '--now', 'mtr-synchost.timer']) |
89 | + |
90 | + else: |
91 | + if os.path.exists(mtr_service) or os.path.exists(mtr_timer): |
92 | + status.maintenance('Disabling systemd mtr timer & service with sync-host {}'.format(config['sync-host'])) |
93 | + if os.path.exists(mtr_service): |
94 | + subprocess.call(['systemctl', 'disable', '--now', 'mtr-synchost.service']) |
95 | + os.unlink(mtr_service) |
96 | + if os.path.exists(mtr_timer): |
97 | + subprocess.call(['systemctl', 'disable', '--now', 'mtr-synchost.timer']) |
98 | + os.unlink(mtr_timer) |
99 | + subprocess.call(['systemctl', 'daemon-reload']) |
100 | + |
101 | + reactive.clear_flag('ubuntu-repository-cache.update-systemd-mtr-required') |
102 | + |
103 | + |
104 | # LP:1770071: Work around charm-helper's unison ownership |
105 | # https://github.com/juju/charm-helpers/issues/487 |
106 | def _fix_ssh_ownership(user='www-sync'): |
107 | @@ -331,6 +379,12 @@ |
108 | os.chown(fname, uid, -1) |
109 | |
110 | |
111 | +def _copy_file(source_path, dest_path, **kwargs): |
112 | + with open(source_path, 'r') as f: |
113 | + source = f.read() |
114 | + return _write_file(source, dest_path, **kwargs) |
115 | + |
116 | + |
117 | def _write_file(source, dest_path, perms=0o644, owner=None, group=None): |
118 | """Write file only on changes and return True if changes written.""" |
119 | # Compare and only write out file on change. |
120 | |
121 | === added directory 'templates/systemd' |
122 | === added file 'templates/systemd/mtr-synchost.service' |
123 | --- templates/systemd/mtr-synchost.service 1970-01-01 00:00:00 +0000 |
124 | +++ templates/systemd/mtr-synchost.service 2022-08-04 02:35:54 +0000 |
125 | @@ -0,0 +1,15 @@ |
126 | +[Unit] |
127 | +Description=Monitor path to sync host regularly |
128 | +Wants=network-online.target |
129 | +After=network-online.target |
130 | + |
131 | +[Service] |
132 | +Type=simple |
133 | +ExecStart=/usr/bin/mtr -z -c7 --tcp -P 80 --report-wide {{sync_host}} |
134 | +ExecStop= |
135 | +User=nobody |
136 | +Restart=on-failure |
137 | +TimeoutSec=5m |
138 | + |
139 | +[Install] |
140 | +WantedBy=multi-user.target |
141 | |
142 | === modified file 'tests/unit/test_ubuntu_repository_cache.py' |
143 | --- tests/unit/test_ubuntu_repository_cache.py 2022-08-01 01:24:02 +0000 |
144 | +++ tests/unit/test_ubuntu_repository_cache.py 2022-08-04 02:35:54 +0000 |
145 | @@ -48,7 +48,10 @@ |
146 | patcher = mock.patch('charmhelpers.core.hookenv.config') |
147 | self.mock_config = patcher.start() |
148 | self.addCleanup(patcher.stop) |
149 | - self.mock_config.return_value = {'nagios_context': 'juju'} |
150 | + self.mock_config.return_value = { |
151 | + 'nagios_context': 'juju', |
152 | + 'sync-host': 'archive.ubuntu.com', |
153 | + } |
154 | |
155 | patcher = mock.patch('charmhelpers.core.host.log') |
156 | self.mock_log = patcher.start() |
157 | @@ -62,6 +65,19 @@ |
158 | if os.path.exists('.juju-persistent-config'): |
159 | os.unlink('.juju-persistent-config') |
160 | |
161 | + @mock.patch('charms.reactive.clear_flag') |
162 | + @mock.patch('charms.reactive.set_flag') |
163 | + def test_upgrade_charm(self, set_flag, clear_flag): |
164 | + ubuntu_repository_cache.upgrade_charm() |
165 | + status.maintenance.assert_called_once_with('Upgrading ubuntu-repository-cache') |
166 | + want = [ |
167 | + mock.call('ubuntu-repository-cache.active'), |
168 | + mock.call('ubuntu-repository-cache.configured'), |
169 | + mock.call('nagios-nrpe.configured'), |
170 | + ] |
171 | + clear_flag.assert_has_calls(want, any_order=True) |
172 | + set_flag.assert_called_once_with('ubuntu-repository-cache.update-systemd-mtr-required') |
173 | + |
174 | @mock.patch('charmhelpers.core.hookenv.leader_get') |
175 | @mock.patch('charms.reactive.set_flag') |
176 | def test_set_active(self, set_flag, leader_get): |
177 | @@ -113,6 +129,115 @@ |
178 | ubuntu_repository_cache.set_active(os.path.join(self.charm_dir, 'tests/unit/files/version5')) |
179 | status.active.assert_called_once_with('Ready (source version/commit commit-id)') |
180 | |
181 | + @mock.patch('charms.reactive.set_flag') |
182 | + def test_update_systemd_mtr_required(self, set_flag): |
183 | + ubuntu_repository_cache.update_systemd_mtr_required() |
184 | + set_flag.assert_called_once_with('ubuntu-repository-cache.update-systemd-mtr-required') |
185 | + |
186 | + @mock.patch('charms.reactive.clear_flag') |
187 | + @mock.patch('subprocess.call') |
188 | + def test_update_systemd_mtr(self, call, clear_flag): |
189 | + self.mock_config.return_value['enable_sync-host_monitoring'] = True |
190 | + ubuntu_repository_cache.update_systemd_mtr(self.tmpdir) |
191 | + want = [ |
192 | + mock.call('ubuntu-repository-cache.active'), |
193 | + mock.call('ubuntu-repository-cache.update-systemd-mtr-required'), |
194 | + ] |
195 | + clear_flag.assert_has_calls(want, any_order=True) |
196 | + want = [ |
197 | + mock.call(['systemctl', 'daemon-reload']), |
198 | + mock.call(['systemctl', 'enable', '--now', 'mtr-synchost.timer']), |
199 | + ] |
200 | + call.assert_has_calls(want, any_order=True) |
201 | + |
202 | + want = '''[Unit] |
203 | +Description=Monitor path to sync host regularly |
204 | +Wants=network-online.target |
205 | +After=network-online.target |
206 | + |
207 | +[Service] |
208 | +Type=simple |
209 | +ExecStart=/usr/bin/mtr -z -c7 --tcp -P 80 --report-wide archive.ubuntu.com |
210 | +ExecStop= |
211 | +User=nobody |
212 | +Restart=on-failure |
213 | +TimeoutSec=5m |
214 | + |
215 | +[Install] |
216 | +WantedBy=multi-user.target |
217 | +''' # NOQA: E501 |
218 | + with open(os.path.join(self.tmpdir, 'mtr-synchost.service'), 'r', encoding='utf-8') as f: |
219 | + got = f.read() |
220 | + self.assertEqual(want, got) |
221 | + |
222 | + with open('files/systemd/mtr-synchost.timer', 'r', encoding='utf-8') as f: |
223 | + want = f.read() |
224 | + with open(os.path.join(self.tmpdir, 'mtr-synchost.timer'), 'r', encoding='utf-8') as f: |
225 | + got = f.read() |
226 | + self.assertEqual(want, got) |
227 | + |
228 | + call.reset_mock() |
229 | + ubuntu_repository_cache.update_systemd_mtr(self.tmpdir) |
230 | + call.assert_not_called() |
231 | + |
232 | + call.reset_mock() |
233 | + self.mock_config.return_value['enable_sync-host_monitoring'] = False |
234 | + ubuntu_repository_cache.update_systemd_mtr(self.tmpdir) |
235 | + want = [ |
236 | + mock.call('ubuntu-repository-cache.active'), |
237 | + mock.call('ubuntu-repository-cache.update-systemd-mtr-required'), |
238 | + ] |
239 | + clear_flag.assert_has_calls(want, any_order=True) |
240 | + want = [ |
241 | + mock.call(['systemctl', 'disable', '--now', 'mtr-synchost.service']), |
242 | + mock.call(['systemctl', 'disable', '--now', 'mtr-synchost.timer']), |
243 | + mock.call(['systemctl', 'daemon-reload']), |
244 | + ] |
245 | + call.assert_has_calls(want, any_order=True) |
246 | + |
247 | + call.reset_mock() |
248 | + self.mock_config.return_value['enable_sync-host_monitoring'] = False |
249 | + ubuntu_repository_cache.update_systemd_mtr(self.tmpdir) |
250 | + call.assert_not_called() |
251 | + |
252 | + call.reset_mock() |
253 | + with open(os.path.join(self.tmpdir, 'mtr-synchost.service'), 'w') as f: |
254 | + f.write("Testing") |
255 | + self.mock_config.return_value['enable_sync-host_monitoring'] = False |
256 | + ubuntu_repository_cache.update_systemd_mtr(self.tmpdir) |
257 | + want = [ |
258 | + mock.call(['systemctl', 'disable', '--now', 'mtr-synchost.service']), |
259 | + mock.call(['systemctl', 'daemon-reload']), |
260 | + ] |
261 | + call.assert_has_calls(want, any_order=True) |
262 | + |
263 | + call.reset_mock() |
264 | + self.mock_config.return_value['enable_sync-host_monitoring'] = False |
265 | + with open(os.path.join(self.tmpdir, 'mtr-synchost.timer'), 'w') as f: |
266 | + f.write("Testing") |
267 | + ubuntu_repository_cache.update_systemd_mtr(self.tmpdir) |
268 | + ubuntu_repository_cache.update_systemd_mtr(self.tmpdir) |
269 | + want = [ |
270 | + mock.call(['systemctl', 'disable', '--now', 'mtr-synchost.timer']), |
271 | + mock.call(['systemctl', 'daemon-reload']), |
272 | + ] |
273 | + call.assert_has_calls(want, any_order=True) |
274 | + |
275 | + def test__copy_file(self): |
276 | + source = os.path.join(self.charm_dir, 'metadata.yaml') |
277 | + dest = os.path.join(self.tmpdir, os.path.basename(source)) |
278 | + |
279 | + self.assertTrue(ubuntu_repository_cache._copy_file(source, dest)) |
280 | + # Write again, should return False and not True per above. |
281 | + self.assertFalse(ubuntu_repository_cache._copy_file(source, dest)) |
282 | + |
283 | + # Check contents |
284 | + with open(source, 'r') as f: |
285 | + want = f.read() |
286 | + with open(dest, 'r') as f: |
287 | + got = f.read() |
288 | + self.assertEqual(got, want) |
289 | + |
290 | def test__write_file(self): |
291 | source = '# User-provided config added here' |
292 | dest = os.path.join(self.tmpdir, 'my-test-file') |
This merge proposal is being monitored by mergebot. Change the status to Approved to merge.