Merge ~xavpaice/charm-sysconfig:linting into charm-sysconfig:master
- Git
- lp:~xavpaice/charm-sysconfig
- linting
- Merge into master
Proposed by
Xav Paice
Status: | Merged |
---|---|
Approved by: | Alvaro Uria |
Approved revision: | daa3c31148f5d43c215db362ab7ffe992f726167 |
Merged at revision: | 1b3e8bb26e059993187aaf1485a761ecbbd95bba |
Proposed branch: | ~xavpaice/charm-sysconfig:linting |
Merge into: | charm-sysconfig:master |
Diff against target: |
1916 lines (+501/-460) 8 files modified
src/lib/lib_sysconfig.py (+130/-103) src/reactive/sysconfig.py (+67/-52) src/tests/functional/conftest.py (+11/-10) src/tests/functional/juju_tools.py (+18/-12) src/tests/functional/test_deploy.py (+160/-195) src/tests/unit/conftest.py (+14/-12) src/tests/unit/test_lib.py (+96/-74) src/tox.ini (+5/-2) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alvaro Uria (community) | Approve | ||
Review via email: mp+388354@code.launchpad.net |
Commit message
Re-lint using Black standard
Description of the change
To post a comment you must log in.
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote : | # |
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote : | # |
Change successfully merged at revision 1b3e8bb26e05999
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/src/lib/lib_sysconfig.py b/src/lib/lib_sysconfig.py |
2 | index 803ae20..475812c 100644 |
3 | --- a/src/lib/lib_sysconfig.py |
4 | +++ b/src/lib/lib_sysconfig.py |
5 | @@ -18,18 +18,18 @@ from charms.reactive.helpers import any_file_changed |
6 | import yaml |
7 | |
8 | |
9 | -GRUB_DEFAULT = 'Advanced options for Ubuntu>Ubuntu, with Linux {}' |
10 | -CPUFREQUTILS_TMPL = 'cpufrequtils.j2' |
11 | -GRUB_CONF_TMPL = 'grub.j2' |
12 | -SYSTEMD_SYSTEM_TMPL = 'etc.systemd.system.conf.j2' |
13 | -SYSTEMD_RESOLVED_TMPL = 'etc.systemd.resolved.conf.j2' |
14 | +GRUB_DEFAULT = "Advanced options for Ubuntu>Ubuntu, with Linux {}" |
15 | +CPUFREQUTILS_TMPL = "cpufrequtils.j2" |
16 | +GRUB_CONF_TMPL = "grub.j2" |
17 | +SYSTEMD_SYSTEM_TMPL = "etc.systemd.system.conf.j2" |
18 | +SYSTEMD_RESOLVED_TMPL = "etc.systemd.resolved.conf.j2" |
19 | |
20 | -CPUFREQUTILS = '/etc/default/cpufrequtils' |
21 | -GRUB_CONF = '/etc/default/grub.d/90-sysconfig.cfg' |
22 | -SYSTEMD_SYSTEM = '/etc/systemd/system.conf' |
23 | -SYSTEMD_RESOLVED = '/etc/systemd/resolved.conf' |
24 | -SYSCTL_CONF = '/etc/sysctl.d/90-charm-sysconfig.conf' |
25 | -KERNEL = 'kernel' |
26 | +CPUFREQUTILS = "/etc/default/cpufrequtils" |
27 | +GRUB_CONF = "/etc/default/grub.d/90-sysconfig.cfg" |
28 | +SYSTEMD_SYSTEM = "/etc/systemd/system.conf" |
29 | +SYSTEMD_RESOLVED = "/etc/systemd/resolved.conf" |
30 | +SYSCTL_CONF = "/etc/sysctl.d/90-charm-sysconfig.conf" |
31 | +KERNEL = "kernel" |
32 | |
33 | |
34 | def parse_config_flags(config_flags): |
35 | @@ -41,15 +41,15 @@ def parse_config_flags(config_flags): |
36 | key_value_pairs = config_flags.split(",") |
37 | parsed_config_flags = {} |
38 | for index, pair in enumerate(key_value_pairs): |
39 | - if '=' in pair: |
40 | - key, value = map(str.strip, pair.split('=', 1)) |
41 | + if "=" in pair: |
42 | + key, value = map(str.strip, pair.split("=", 1)) |
43 | # Note(peppepetra): if value contains a comma that is also used as |
44 | # delimiter, we need to reconstruct the value |
45 | i = index + 1 |
46 | while i < len(key_value_pairs): |
47 | - if '=' in key_value_pairs[i]: |
48 | + if "=" in key_value_pairs[i]: |
49 | break |
50 | - value += ',' + key_value_pairs[i] |
51 | + value += "," + key_value_pairs[i] |
52 | i += 1 |
53 | parsed_config_flags[key] = value |
54 | return parsed_config_flags |
55 | @@ -62,7 +62,7 @@ def running_kernel(): |
56 | |
57 | def boot_time(): |
58 | """Return timestamp of last boot.""" |
59 | - with open('/proc/uptime', 'r') as f: |
60 | + with open("/proc/uptime", "r") as f: |
61 | uptime_seconds = float(f.readline().split()[0]) |
62 | boot_time = datetime.now(timezone.utc) - timedelta(seconds=uptime_seconds) |
63 | return boot_time |
64 | @@ -84,7 +84,7 @@ class BootResourceState: |
65 | def calculate_resource_sha256sum(self, resource_name): |
66 | """Calcucate sha256sum of contents of provided resource.""" |
67 | sha = hashlib.sha256() |
68 | - sha.update(open(resource_name, 'rb').read()) |
69 | + sha.update(open(resource_name, "rb").read()) |
70 | return sha.hexdigest() |
71 | |
72 | def update_resource_checksums(self, resources): |
73 | @@ -93,8 +93,10 @@ class BootResourceState: |
74 | if not os.path.exists(resource): |
75 | continue |
76 | |
77 | - self.db.set("{}.sha256sum".format(self.key_for(resource)), |
78 | - self.calculate_resource_sha256sum(resource)) |
79 | + self.db.set( |
80 | + "{}.sha256sum".format(self.key_for(resource)), |
81 | + self.calculate_resource_sha256sum(resource), |
82 | + ) |
83 | |
84 | def set_resource(self, resource_name): |
85 | """Update db entry for the resource_name with time.now.""" |
86 | @@ -116,7 +118,9 @@ class BootResourceState: |
87 | tfloat = self.db.get(self.key_for(resource_name)) |
88 | if tfloat is not None: |
89 | return datetime.fromtimestamp(tfloat, timezone.utc) |
90 | - return datetime.min.replace(tzinfo=timezone.utc) # We don't have a ts -> changed at dawn of time |
91 | + return datetime.min.replace( |
92 | + tzinfo=timezone.utc |
93 | + ) # We don't have a ts -> changed at dawn of time |
94 | |
95 | def checksum_changed(self, resource_name): |
96 | """Return True if checksum has changed since last recorded.""" |
97 | @@ -139,11 +143,13 @@ class BootResourceState: |
98 | :return: list of names |
99 | """ |
100 | boot_ts = boot_time() |
101 | - time_changed = [name for name in resource_names |
102 | - if boot_ts < self.get_resource_changed_timestamp(name)] |
103 | + time_changed = [ |
104 | + name |
105 | + for name in resource_names |
106 | + if boot_ts < self.get_resource_changed_timestamp(name) |
107 | + ] |
108 | |
109 | - csum_changed = [name for name in resource_names |
110 | - if self.checksum_changed(name)] |
111 | + csum_changed = [name for name in resource_names if self.checksum_changed(name)] |
112 | |
113 | a = set(time_changed) |
114 | b = set(csum_changed) |
115 | @@ -172,7 +178,7 @@ class SysConfigHelper: |
116 | @property |
117 | def enable_container(self): |
118 | """Return enable-container config.""" |
119 | - return self.charm_config['enable-container'] |
120 | + return self.charm_config["enable-container"] |
121 | |
122 | @property |
123 | def reservation(self): |
124 | @@ -181,14 +187,14 @@ class SysConfigHelper: |
125 | [DEPRECATED]: this option should no longer be used. |
126 | Instead cpu-affinity-range and isolcpus should be used. |
127 | """ |
128 | - return self.charm_config['reservation'] |
129 | + return self.charm_config["reservation"] |
130 | |
131 | @property |
132 | def cpu_affinity_range(self): |
133 | """Return cpu-affinity-range config.""" |
134 | if self.reservation == "affinity" and self.cpu_range: |
135 | return self.cpu_range |
136 | - return self.charm_config['cpu-affinity-range'] |
137 | + return self.charm_config["cpu-affinity-range"] |
138 | |
139 | @property |
140 | def cpu_range(self): |
141 | @@ -197,84 +203,81 @@ class SysConfigHelper: |
142 | [DEPRECATED]: this option should no longer be used. |
143 | Instead cpu-affinity-range and isolcpus should be used. |
144 | """ |
145 | - return self.charm_config['cpu-range'] |
146 | + return self.charm_config["cpu-range"] |
147 | |
148 | @property |
149 | def hugepages(self): |
150 | """Return hugepages config.""" |
151 | - return self.charm_config['hugepages'] |
152 | + return self.charm_config["hugepages"] |
153 | |
154 | @property |
155 | def hugepagesz(self): |
156 | """Return hugepagesz config.""" |
157 | - return self.charm_config['hugepagesz'] |
158 | + return self.charm_config["hugepagesz"] |
159 | |
160 | @property |
161 | def isolcpus(self): |
162 | """Return isolcpus config.""" |
163 | if self.reservation == "isolcpus" and self.cpu_range: |
164 | return self.cpu_range |
165 | - return self.charm_config['isolcpus'] |
166 | + return self.charm_config["isolcpus"] |
167 | |
168 | @property |
169 | def raid_autodetection(self): |
170 | """Return raid-autodetection config option.""" |
171 | - return self.charm_config['raid-autodetection'] |
172 | + return self.charm_config["raid-autodetection"] |
173 | |
174 | @property |
175 | def enable_pti(self): |
176 | """Return raid-autodetection config option.""" |
177 | - return self.charm_config['enable-pti'] |
178 | + return self.charm_config["enable-pti"] |
179 | |
180 | @property |
181 | def enable_iommu(self): |
182 | """Return enable-iommu config option.""" |
183 | - return self.charm_config['enable-iommu'] |
184 | + return self.charm_config["enable-iommu"] |
185 | |
186 | @property |
187 | def grub_config_flags(self): |
188 | """Return grub-config-flags config option.""" |
189 | - return parse_config_flags(self.charm_config['grub-config-flags']) |
190 | + return parse_config_flags(self.charm_config["grub-config-flags"]) |
191 | |
192 | @property |
193 | def systemd_config_flags(self): |
194 | """Return systemd-config-flags config option.""" |
195 | - return parse_config_flags(self.charm_config['systemd-config-flags']) |
196 | + return parse_config_flags(self.charm_config["systemd-config-flags"]) |
197 | |
198 | @property |
199 | def kernel_version(self): |
200 | """Return kernel-version config option.""" |
201 | - return self.charm_config['kernel-version'] |
202 | + return self.charm_config["kernel-version"] |
203 | |
204 | @property |
205 | def update_grub(self): |
206 | """Return update-grub config option.""" |
207 | - return self.charm_config['update-grub'] |
208 | + return self.charm_config["update-grub"] |
209 | |
210 | @property |
211 | def governor(self): |
212 | """Return governor config option.""" |
213 | - return self.charm_config['governor'] |
214 | + return self.charm_config["governor"] |
215 | |
216 | @property |
217 | def resolved_cache_mode(self): |
218 | """Return resolved-cache-mode config option.""" |
219 | - return self.charm_config['resolved-cache-mode'] |
220 | + return self.charm_config["resolved-cache-mode"] |
221 | |
222 | @property |
223 | def sysctl_config(self): |
224 | """Return sysctl config option.""" |
225 | - raw_str = self.charm_config['sysctl'] |
226 | + raw_str = self.charm_config["sysctl"] |
227 | |
228 | try: |
229 | parsed = yaml.safe_load(raw_str) |
230 | except yaml.YAMLError: |
231 | err_msg = "Error parsing sysctl YAML" |
232 | - hookenv.status_set('blocked', err_msg) |
233 | - hookenv.log( |
234 | - "%s: %s" % (err_msg, raw_str), |
235 | - level=hookenv.ERROR |
236 | - ) |
237 | + hookenv.status_set("blocked", err_msg) |
238 | + hookenv.log("%s: %s" % (err_msg, raw_str), level=hookenv.ERROR) |
239 | raise |
240 | |
241 | return parsed |
242 | @@ -286,9 +289,9 @@ class SysConfigHelper: |
243 | [DEPRECATED]: this option should no longer be used. |
244 | Instead grub-config-flags and systemd-config-flags should be used. |
245 | """ |
246 | - if not self.charm_config.get('config-flags'): |
247 | + if not self.charm_config.get("config-flags"): |
248 | return {} |
249 | - flags = config_flags_parser(self.charm_config['config-flags']) |
250 | + flags = config_flags_parser(self.charm_config["config-flags"]) |
251 | return flags |
252 | |
253 | def _render_boot_resource(self, source, target, context): |
254 | @@ -299,10 +302,10 @@ class SysConfigHelper: |
255 | @staticmethod |
256 | def _render_resource(source, target, context): |
257 | """Render the template.""" |
258 | - render(source=source, templates_dir='templates', target=target, context=context) |
259 | + render(source=source, templates_dir="templates", target=target, context=context) |
260 | |
261 | def _is_kernel_already_running(self): |
262 | - """Check if the kernel version required by charm config is equal to kernel running.""" |
263 | + """Check if the kernel version required by charm config = kernel running.""" |
264 | configured = self.kernel_version |
265 | if configured == running_kernel(): |
266 | hookenv.log("Already running kernel: {}".format(configured), hookenv.DEBUG) |
267 | @@ -312,21 +315,34 @@ class SysConfigHelper: |
268 | def _update_grub(self): |
269 | """Call update-grub when update-grub config param is set to True.""" |
270 | if self.update_grub and not host.is_container(): |
271 | - subprocess.check_call(['/usr/sbin/update-grub']) |
272 | - hookenv.log('Running update-grub to apply grub conf updates', hookenv.DEBUG) |
273 | + subprocess.check_call(["/usr/sbin/update-grub"]) |
274 | + hookenv.log("Running update-grub to apply grub conf updates", hookenv.DEBUG) |
275 | |
276 | def is_config_valid(self): |
277 | """Validate config parameters.""" |
278 | valid = True |
279 | |
280 | for config_key, value, valid_values in ( |
281 | - ('reservation', self.reservation, ['off', 'isolcpus', 'affinity']), |
282 | - ('raid-autodetection', self.raid_autodetection, ['', 'noautodetect', 'partitionable']), |
283 | - ('governor', self.governor, ['', 'powersave', 'performance']), |
284 | - ('resolved-cache-mode', self.resolved_cache_mode, ['', 'yes', 'no', 'no-negative']), |
285 | + ("reservation", self.reservation, ["off", "isolcpus", "affinity"]), |
286 | + ( |
287 | + "raid-autodetection", |
288 | + self.raid_autodetection, |
289 | + ["", "noautodetect", "partitionable"], |
290 | + ), |
291 | + ("governor", self.governor, ["", "powersave", "performance"]), |
292 | + ( |
293 | + "resolved-cache-mode", |
294 | + self.resolved_cache_mode, |
295 | + ["", "yes", "no", "no-negative"], |
296 | + ), |
297 | ): |
298 | if value not in valid_values: |
299 | - hookenv.log('{} not valid. Possible values: {}'.format(config_key, repr(valid_values)), hookenv.DEBUG) |
300 | + hookenv.log( |
301 | + "{} not valid. Possible values: {}".format( |
302 | + config_key, repr(valid_values) |
303 | + ), |
304 | + hookenv.DEBUG, |
305 | + ) |
306 | valid = False |
307 | |
308 | return valid |
309 | @@ -347,60 +363,64 @@ class SysConfigHelper: |
310 | # This is to keep the old method of specifying the isolcpus |
311 | # by specifying the reservation and the cpu_range |
312 | if self.isolcpus: |
313 | - context['isolcpus'] = self.isolcpus |
314 | + context["isolcpus"] = self.isolcpus |
315 | if self.hugepages: |
316 | - context['hugepages'] = self.hugepages |
317 | + context["hugepages"] = self.hugepages |
318 | if self.hugepagesz: |
319 | - context['hugepagesz'] = self.hugepagesz |
320 | + context["hugepagesz"] = self.hugepagesz |
321 | if self.raid_autodetection: |
322 | - context['raid'] = self.raid_autodetection |
323 | + context["raid"] = self.raid_autodetection |
324 | if not self.enable_pti: |
325 | - context['pti_off'] = True |
326 | + context["pti_off"] = True |
327 | if self.enable_iommu: |
328 | - context['iommu'] = True |
329 | + context["iommu"] = True |
330 | |
331 | # Note(peppepetra): First check if new grub-config-flags is used |
332 | # if not try to fallback into legacy config-flags |
333 | if self.grub_config_flags: |
334 | - context['grub_config_flags'] = self.grub_config_flags |
335 | + context["grub_config_flags"] = self.grub_config_flags |
336 | else: |
337 | - context['grub_config_flags'] = parse_config_flags(self.config_flags.get('grub', '')) |
338 | + context["grub_config_flags"] = parse_config_flags( |
339 | + self.config_flags.get("grub", "") |
340 | + ) |
341 | |
342 | if self.kernel_version and not self._is_kernel_already_running(): |
343 | - context['grub_default'] = GRUB_DEFAULT.format(self.kernel_version) |
344 | + context["grub_default"] = GRUB_DEFAULT.format(self.kernel_version) |
345 | |
346 | self._render_boot_resource(GRUB_CONF_TMPL, GRUB_CONF, context) |
347 | - hookenv.log('grub configuration updated') |
348 | + hookenv.log("grub configuration updated") |
349 | self._update_grub() |
350 | |
351 | def update_systemd_system_file(self): |
352 | """Update /etc/systemd/system.conf according to charm configuration.""" |
353 | context = {} |
354 | if self.cpu_affinity_range: |
355 | - context['cpu_affinity_range'] = self.cpu_affinity_range |
356 | + context["cpu_affinity_range"] = self.cpu_affinity_range |
357 | |
358 | # Note(peppepetra): First check if new systemd-config-flags is used |
359 | # if not try to fallback into legacy config-flags |
360 | if self.systemd_config_flags: |
361 | - context['systemd_config_flags'] = self.systemd_config_flags |
362 | + context["systemd_config_flags"] = self.systemd_config_flags |
363 | else: |
364 | - context['systemd_config_flags'] = parse_config_flags(self.config_flags.get('systemd', '')) |
365 | + context["systemd_config_flags"] = parse_config_flags( |
366 | + self.config_flags.get("systemd", "") |
367 | + ) |
368 | |
369 | self._render_boot_resource(SYSTEMD_SYSTEM_TMPL, SYSTEMD_SYSTEM, context) |
370 | - hookenv.log('systemd configuration updated') |
371 | + hookenv.log("systemd configuration updated") |
372 | |
373 | def update_systemd_resolved(self): |
374 | """Update /etc/systemd/resolved.conf according to charm configuration.""" |
375 | context = {} |
376 | if self.resolved_cache_mode: |
377 | - context['cache'] = self.resolved_cache_mode |
378 | + context["cache"] = self.resolved_cache_mode |
379 | self._update_systemd_resolved(context) |
380 | - hookenv.log('systemd-resolved configuration updated') |
381 | + hookenv.log("systemd-resolved configuration updated") |
382 | |
383 | def update_sysctl(self): |
384 | """Update sysctl according to charm configuration.""" |
385 | sysctl.create(self.sysctl_config or {}, SYSCTL_CONF) |
386 | - hookenv.log('sysctl updated') |
387 | + hookenv.log("sysctl updated") |
388 | |
389 | def install_configured_kernel(self): |
390 | """Install kernel as given by the kernel-version config option. |
391 | @@ -408,14 +428,14 @@ class SysConfigHelper: |
392 | Will install kernel and matching modules-extra package |
393 | """ |
394 | if not self.kernel_version or self._is_kernel_already_running(): |
395 | - hookenv.log( |
396 | - 'Kernel is already running the required version', |
397 | - hookenv.DEBUG |
398 | - ) |
399 | + hookenv.log("Kernel is already running the required version", hookenv.DEBUG) |
400 | return |
401 | |
402 | configured = self.kernel_version |
403 | - pkgs = [tmpl.format(configured) for tmpl in ["linux-image-{}", "linux-modules-extra-{}"]] |
404 | + pkgs = [ |
405 | + tmpl.format(configured) |
406 | + for tmpl in ["linux-image-{}", "linux-modules-extra-{}"] |
407 | + ] |
408 | apt_update() |
409 | apt_install(pkgs) |
410 | hookenv.log("installing: {}".format(pkgs)) |
411 | @@ -423,28 +443,34 @@ class SysConfigHelper: |
412 | |
413 | def update_cpufreq(self): |
414 | """Update /etc/default/cpufrequtils and restart cpufrequtils service.""" |
415 | - if self.governor not in ('', 'performance', 'powersave'): |
416 | + if self.governor not in ("", "performance", "powersave"): |
417 | return |
418 | - context = {'governor': self.governor} |
419 | + context = {"governor": self.governor} |
420 | self._render_boot_resource(CPUFREQUTILS_TMPL, CPUFREQUTILS, context) |
421 | - # Ensure the ondemand service is disabled if governor is set, lp#1822774, lp#1863659, lp#740127 |
422 | + # Ensure the ondemand service is disabled if governor is set, |
423 | + # lp#1822774, lp#1863659, lp#740127 |
424 | # Ondemand service is not updated during test if host is container. |
425 | if not host.is_container(): |
426 | - hookenv.log('disabling the ondemand services for lp#1822774, lp#1863659,' |
427 | - ' and lp#740127 if a governor is specified', hookenv.DEBUG) |
428 | + hookenv.log( |
429 | + "disabling the ondemand services for lp#1822774, lp#1863659," |
430 | + " and lp#740127 if a governor is specified", |
431 | + hookenv.DEBUG, |
432 | + ) |
433 | if self.governor: |
434 | subprocess.call( |
435 | - ['/bin/systemctl', 'mask', 'ondemand'], |
436 | - stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL |
437 | + ["/bin/systemctl", "mask", "ondemand"], |
438 | + stdout=subprocess.DEVNULL, |
439 | + stderr=subprocess.DEVNULL, |
440 | ) |
441 | else: |
442 | # Renable ondemand when governor is unset. |
443 | subprocess.call( |
444 | - ['/bin/systemctl', 'unmask', 'ondemand'], |
445 | - stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL |
446 | + ["/bin/systemctl", "unmask", "ondemand"], |
447 | + stdout=subprocess.DEVNULL, |
448 | + stderr=subprocess.DEVNULL, |
449 | ) |
450 | |
451 | - host.service_restart('cpufrequtils') |
452 | + host.service_restart("cpufrequtils") |
453 | |
454 | def remove_grub_configuration(self): |
455 | """Remove /etc/default/grub.d/90-sysconfig.cfg if exists. |
456 | @@ -456,8 +482,8 @@ class SysConfigHelper: |
457 | return |
458 | os.remove(grub_configuration_path) |
459 | hookenv.log( |
460 | - 'deleted grub configuration at {}'.format(grub_configuration_path), |
461 | - hookenv.DEBUG |
462 | + "deleted grub configuration at {}".format(grub_configuration_path), |
463 | + hookenv.DEBUG, |
464 | ) |
465 | self._update_grub() |
466 | self.boot_resources.set_resource(GRUB_CONF) |
467 | @@ -470,8 +496,7 @@ class SysConfigHelper: |
468 | context = {} |
469 | self._render_boot_resource(SYSTEMD_SYSTEM_TMPL, SYSTEMD_SYSTEM, context) |
470 | hookenv.log( |
471 | - 'deleted systemd configuration at {}'.format(SYSTEMD_SYSTEM), |
472 | - hookenv.DEBUG |
473 | + "deleted systemd configuration at {}".format(SYSTEMD_SYSTEM), hookenv.DEBUG |
474 | ) |
475 | |
476 | def remove_resolved_configuration(self): |
477 | @@ -481,14 +506,14 @@ class SysConfigHelper: |
478 | """ |
479 | self._update_systemd_resolved({}) |
480 | hookenv.log( |
481 | - 'deleted resolved configuration at {}'.format(SYSTEMD_RESOLVED), |
482 | - hookenv.DEBUG |
483 | + "deleted resolved configuration at {}".format(SYSTEMD_RESOLVED), |
484 | + hookenv.DEBUG, |
485 | ) |
486 | |
487 | def _update_systemd_resolved(self, context): |
488 | self._render_resource(SYSTEMD_RESOLVED_TMPL, SYSTEMD_RESOLVED, context) |
489 | if any_file_changed([SYSTEMD_RESOLVED]): |
490 | - host.service_restart('systemd-resolved') |
491 | + host.service_restart("systemd-resolved") |
492 | |
493 | def remove_cpufreq_configuration(self): |
494 | """Remove cpufrequtils configuration. |
495 | @@ -497,16 +522,18 @@ class SysConfigHelper: |
496 | """ |
497 | context = {} |
498 | if not host.is_container(): |
499 | - hookenv.log('Enabling the ondemand initscript for lp#1822774' |
500 | - ' and lp#740127', 'DEBUG') |
501 | + hookenv.log( |
502 | + "Enabling the ondemand initscript for lp#1822774" " and lp#740127", |
503 | + "DEBUG", |
504 | + ) |
505 | subprocess.call( |
506 | - ['/bin/systemctl', 'unmask', 'ondemand'], |
507 | - stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL |
508 | + ["/bin/systemctl", "unmask", "ondemand"], |
509 | + stdout=subprocess.DEVNULL, |
510 | + stderr=subprocess.DEVNULL, |
511 | ) |
512 | |
513 | self._render_boot_resource(CPUFREQUTILS_TMPL, CPUFREQUTILS, context) |
514 | hookenv.log( |
515 | - 'deleted cpufreq configuration at {}'.format(CPUFREQUTILS), |
516 | - hookenv.DEBUG |
517 | + "deleted cpufreq configuration at {}".format(CPUFREQUTILS), hookenv.DEBUG |
518 | ) |
519 | - host.service_restart('cpufrequtils') |
520 | + host.service_restart("cpufrequtils") |
521 | diff --git a/src/reactive/sysconfig.py b/src/reactive/sysconfig.py |
522 | index ecbe0eb..b829d83 100644 |
523 | --- a/src/reactive/sysconfig.py |
524 | +++ b/src/reactive/sysconfig.py |
525 | @@ -29,26 +29,34 @@ from charms.reactive import ( |
526 | when_not, |
527 | ) |
528 | |
529 | -from lib_sysconfig import CPUFREQUTILS, GRUB_CONF, KERNEL, SYSTEMD_RESOLVED, SYSTEMD_SYSTEM, SysConfigHelper |
530 | +from lib_sysconfig import ( |
531 | + CPUFREQUTILS, |
532 | + GRUB_CONF, |
533 | + KERNEL, |
534 | + SYSTEMD_RESOLVED, |
535 | + SYSTEMD_SYSTEM, |
536 | + SysConfigHelper, |
537 | +) |
538 | |
539 | |
540 | -@when_none('sysconfig.installed', 'sysconfig.unsupported') |
541 | -@when('juju-info.connected') |
542 | +@when_none("sysconfig.installed", "sysconfig.unsupported") |
543 | +@when("juju-info.connected") |
544 | def install_sysconfig(): |
545 | """Install the charm if it is not running on a container. |
546 | |
547 | - Deploy can be forced using enable-container option only for testing. (Default: false). |
548 | + Deploy can be forced using enable-container option only for testing. |
549 | + (Default: false). |
550 | """ |
551 | syshelper = SysConfigHelper() |
552 | |
553 | # container not supported unless enable-container=true for testing purpose |
554 | if host.is_container() and not syshelper.enable_container: |
555 | - hookenv.status_set('blocked', 'containers are not supported') |
556 | - set_flag('sysconfig.unsupported') |
557 | + hookenv.status_set("blocked", "containers are not supported") |
558 | + set_flag("sysconfig.unsupported") |
559 | return |
560 | |
561 | if not syshelper.is_config_valid(): |
562 | - hookenv.status_set('blocked', 'configuration parameters not valid.') |
563 | + hookenv.status_set("blocked", "configuration parameters not valid.") |
564 | return |
565 | |
566 | syshelper.install_configured_kernel() |
567 | @@ -56,68 +64,71 @@ def install_sysconfig(): |
568 | syshelper.update_grub_file() |
569 | syshelper.update_systemd_system_file() |
570 | syshelper.update_systemd_resolved() |
571 | - set_flag('sysconfig.installed') |
572 | + set_flag("sysconfig.installed") |
573 | update_status() |
574 | |
575 | |
576 | -@when('sysconfig.installed') |
577 | -@when_not('sysconfig.unsupported') |
578 | -@when('config.changed') |
579 | +@when("sysconfig.installed") |
580 | +@when_not("sysconfig.unsupported") |
581 | +@when("config.changed") |
582 | def config_changed(): |
583 | """Apply configuration updates if the charm is installed.""" |
584 | syshelper = SysConfigHelper() |
585 | - hookenv.status_set('maintenance', 'applying changes') |
586 | + hookenv.status_set("maintenance", "applying changes") |
587 | |
588 | if not syshelper.is_config_valid(): |
589 | - hookenv.status_set('blocked', 'configuration parameters not valid.') |
590 | + hookenv.status_set("blocked", "configuration parameters not valid.") |
591 | return |
592 | |
593 | # Kernel |
594 | - if syshelper.charm_config.changed('kernel-version'): |
595 | + if syshelper.charm_config.changed("kernel-version"): |
596 | syshelper.install_configured_kernel() |
597 | |
598 | # cpufreq |
599 | - if syshelper.charm_config.changed('governor') or helpers.any_file_changed([CPUFREQUTILS]): |
600 | + if syshelper.charm_config.changed("governor") or helpers.any_file_changed( |
601 | + [CPUFREQUTILS] |
602 | + ): |
603 | syshelper.update_cpufreq() |
604 | |
605 | # GRUB |
606 | - if any(syshelper.charm_config.changed(flag) for flag in ( |
607 | - 'reservation', |
608 | - 'hugepages', |
609 | - 'hugepagesz', |
610 | - 'raid-autodetection', |
611 | - 'enable-pti', |
612 | - 'enable-iommu', |
613 | - 'grub-config-flags', |
614 | - 'kernel-version', |
615 | - 'update-grub', |
616 | - 'config-flags', |
617 | - 'cpu-range', |
618 | - )) or helpers.any_file_changed([GRUB_CONF]): |
619 | + if any( |
620 | + syshelper.charm_config.changed(flag) |
621 | + for flag in ( |
622 | + "reservation", |
623 | + "hugepages", |
624 | + "hugepagesz", |
625 | + "raid-autodetection", |
626 | + "enable-pti", |
627 | + "enable-iommu", |
628 | + "grub-config-flags", |
629 | + "kernel-version", |
630 | + "update-grub", |
631 | + "config-flags", |
632 | + "cpu-range", |
633 | + ) |
634 | + ) or helpers.any_file_changed([GRUB_CONF]): |
635 | syshelper.update_grub_file() |
636 | |
637 | # systemd |
638 | - if any(syshelper.charm_config.changed(flag) for flag in ( |
639 | - 'reservation', |
640 | - 'systemd-config-flags', |
641 | - 'cpu-range', |
642 | - 'config-flags', |
643 | - )) or helpers.any_file_changed([SYSTEMD_SYSTEM]): |
644 | + if any( |
645 | + syshelper.charm_config.changed(flag) |
646 | + for flag in ("reservation", "systemd-config-flags", "cpu-range", "config-flags") |
647 | + ) or helpers.any_file_changed([SYSTEMD_SYSTEM]): |
648 | syshelper.update_systemd_system_file() |
649 | |
650 | # systemd resolved |
651 | - if any(syshelper.charm_config.changed(flag) for flag in ( |
652 | - 'resolved-cache-mode', |
653 | - )) or helpers.any_file_changed([SYSTEMD_RESOLVED]): |
654 | + if any( |
655 | + syshelper.charm_config.changed(flag) for flag in ("resolved-cache-mode",) |
656 | + ) or helpers.any_file_changed([SYSTEMD_RESOLVED]): |
657 | syshelper.update_systemd_resolved() |
658 | |
659 | - if syshelper.charm_config.changed('sysctl'): |
660 | + if syshelper.charm_config.changed("sysctl"): |
661 | syshelper.update_sysctl() |
662 | |
663 | update_status() |
664 | |
665 | |
666 | -@hook('upgrade-charm') |
667 | +@hook("upgrade-charm") |
668 | def upgrade_charm(): |
669 | """Extras to run when charm is upgraded.""" |
670 | # NOTE(hopem): do this for backwards compatibility to ensure that db |
671 | @@ -127,44 +138,48 @@ def upgrade_charm(): |
672 | update_status() |
673 | |
674 | |
675 | -@hook('update-status') |
676 | +@hook("update-status") |
677 | def update_status(): |
678 | """Update the workload message checking if reboot is needed. |
679 | |
680 | Note: After the reboot use clear-notification action to clear the |
681 | 'reboot required' message. |
682 | """ |
683 | - if is_flag_set('sysconfig.unsupported'): |
684 | + if is_flag_set("sysconfig.unsupported"): |
685 | return |
686 | |
687 | resources = [KERNEL, SYSTEMD_SYSTEM, GRUB_CONF] |
688 | - boot_changes = SysConfigHelper.boot_resources.resources_changed_since_boot(resources) |
689 | + boot_changes = SysConfigHelper.boot_resources.resources_changed_since_boot( |
690 | + resources |
691 | + ) |
692 | |
693 | if boot_changes: |
694 | - hookenv.status_set('active', 'reboot required. Changes in: {}'.format(', '.join(boot_changes))) |
695 | + hookenv.status_set( |
696 | + "active", "reboot required. Changes in: {}".format(", ".join(boot_changes)) |
697 | + ) |
698 | else: |
699 | - hookenv.status_set('active', 'ready') |
700 | + hookenv.status_set("active", "ready") |
701 | |
702 | |
703 | -@when('config.changed.enable-container') |
704 | -@when_not('sysconfig.installed') |
705 | +@when("config.changed.enable-container") |
706 | +@when_not("sysconfig.installed") |
707 | def enable_container_changed(): |
708 | """Trigger installation if enable-container option changed.""" |
709 | - clear_flag('sysconfig.unsupported') |
710 | + clear_flag("sysconfig.unsupported") |
711 | |
712 | |
713 | -@when('sysconfig.installed') |
714 | -@when_not('juju-info.available') |
715 | +@when("sysconfig.installed") |
716 | +@when_not("juju-info.available") |
717 | def remove_configuration(): |
718 | """Remove configuration applied by the charm if the juju-info relation is departed. |
719 | |
720 | For safety, kernels installed by the charm won't be removed. |
721 | """ |
722 | - hookenv.status_set('maintenance', 'removing sysconfig configurations') |
723 | + hookenv.status_set("maintenance", "removing sysconfig configurations") |
724 | syshelper = SysConfigHelper() |
725 | syshelper.remove_cpufreq_configuration() |
726 | syshelper.remove_grub_configuration() |
727 | syshelper.remove_systemd_configuration() |
728 | syshelper.remove_resolved_configuration() |
729 | - clear_flag('sysconfig.installed') |
730 | - clear_flag('sysconfig.unsupported') |
731 | + clear_flag("sysconfig.installed") |
732 | + clear_flag("sysconfig.unsupported") |
733 | diff --git a/src/tests/functional/conftest.py b/src/tests/functional/conftest.py |
734 | index 29c78fd..f7f32e9 100644 |
735 | --- a/src/tests/functional/conftest.py |
736 | +++ b/src/tests/functional/conftest.py |
737 | @@ -20,7 +20,7 @@ from juju_tools import JujuTools |
738 | import pytest |
739 | |
740 | |
741 | -@pytest.fixture(scope='module') |
742 | +@pytest.fixture(scope="module") |
743 | def event_loop(): |
744 | """Override the default pytest event loop. |
745 | |
746 | @@ -34,7 +34,7 @@ def event_loop(): |
747 | asyncio.set_event_loop(None) |
748 | |
749 | |
750 | -@pytest.fixture(scope='module') |
751 | +@pytest.fixture(scope="module") |
752 | async def controller(): |
753 | """Connect to the current controller.""" |
754 | _controller = Controller() |
755 | @@ -43,27 +43,28 @@ async def controller(): |
756 | await _controller.disconnect() |
757 | |
758 | |
759 | -@pytest.fixture(scope='module') |
760 | +@pytest.fixture(scope="module") |
761 | async def model(controller): |
762 | """Destroy the model at the end of the test.""" |
763 | model_name = "functest-{}".format(str(uuid.uuid4())[-12:]) |
764 | - _model = await controller.add_model(model_name, |
765 | - cloud_name=os.getenv('PYTEST_CLOUD_NAME'), |
766 | - region=os.getenv('PYTEST_CLOUD_REGION'), |
767 | - ) |
768 | + _model = await controller.add_model( |
769 | + model_name, |
770 | + cloud_name=os.getenv("PYTEST_CLOUD_NAME"), |
771 | + region=os.getenv("PYTEST_CLOUD_REGION"), |
772 | + ) |
773 | # https://github.com/juju/python-libjuju/issues/267 |
774 | - subprocess.check_call(['juju', 'models']) |
775 | + subprocess.check_call(["juju", "models"]) |
776 | while model_name not in await controller.list_models(): |
777 | await asyncio.sleep(1) |
778 | yield _model |
779 | await _model.disconnect() |
780 | - if not os.getenv('PYTEST_KEEP_MODEL'): |
781 | + if not os.getenv("PYTEST_KEEP_MODEL"): |
782 | await controller.destroy_model(model_name) |
783 | while model_name in await controller.list_models(): |
784 | await asyncio.sleep(1) |
785 | |
786 | |
787 | -@pytest.fixture(scope='module') |
788 | +@pytest.fixture(scope="module") |
789 | async def jujutools(controller, model): |
790 | """Return JujuTools instance.""" |
791 | tools = JujuTools(controller, model) |
792 | diff --git a/src/tests/functional/juju_tools.py b/src/tests/functional/juju_tools.py |
793 | index c7c791e..71b4aac 100644 |
794 | --- a/src/tests/functional/juju_tools.py |
795 | +++ b/src/tests/functional/juju_tools.py |
796 | @@ -8,7 +8,11 @@ import juju |
797 | |
798 | |
799 | class JujuTools: |
800 | - """Permit to run command in a unit under tests (generic command, os.stat and cat <file>).""" |
801 | + """Helper class to run command in a unit under test. |
802 | + |
803 | + Permit to run command in a unit under tests (generic command, os.stat and |
804 | + cat <file>). |
805 | + """ |
806 | |
807 | def __init__(self, controller, model): |
808 | """Initialize controller and model under test.""" |
809 | @@ -37,14 +41,17 @@ class JujuTools: |
810 | :param target: Unit object or unit name string |
811 | """ |
812 | python3 = "python3 -c '{}'" |
813 | - python_cmd = ('import pickle;' |
814 | - 'import base64;' |
815 | - '{}' |
816 | - 'print(base64.b64encode(pickle.dumps({})), end="")' |
817 | - .format(imports, remote_cmd)) |
818 | + python_cmd = ( |
819 | + "import pickle;" |
820 | + "import base64;" |
821 | + "{}" |
822 | + 'print(base64.b64encode(pickle.dumps({})), end="")'.format( |
823 | + imports, remote_cmd |
824 | + ) |
825 | + ) |
826 | cmd = python3.format(python_cmd) |
827 | results = await self.run_command(cmd, target) |
828 | - return pickle.loads(base64.b64decode(bytes(results['Stdout'][2:-1], 'utf8'))) |
829 | + return pickle.loads(base64.b64decode(bytes(results["Stdout"][2:-1], "utf8"))) |
830 | |
831 | async def file_stat(self, path, target): |
832 | """Run stat on a file. |
833 | @@ -52,9 +59,8 @@ class JujuTools: |
834 | :param path: File path |
835 | :param target: Unit object or unit name string |
836 | """ |
837 | - imports = 'import os;' |
838 | - python_cmd = ('os.stat("{}")' |
839 | - .format(path)) |
840 | + imports = "import os;" |
841 | + python_cmd = 'os.stat("{}")'.format(path) |
842 | print("Calling remote cmd: " + python_cmd) |
843 | return await self.remote_object(imports, python_cmd, target) |
844 | |
845 | @@ -64,6 +70,6 @@ class JujuTools: |
846 | :param path: File path |
847 | :param target: Unit object or unit name string |
848 | """ |
849 | - cmd = 'cat {}'.format(path) |
850 | + cmd = "cat {}".format(path) |
851 | result = await self.run_command(cmd, target) |
852 | - return result['Stdout'] |
853 | + return result["Stdout"] |
854 | diff --git a/src/tests/functional/test_deploy.py b/src/tests/functional/test_deploy.py |
855 | index ea85064..84b2cd3 100644 |
856 | --- a/src/tests/functional/test_deploy.py |
857 | +++ b/src/tests/functional/test_deploy.py |
858 | @@ -13,20 +13,16 @@ import websockets |
859 | # Treat all tests as coroutines |
860 | pytestmark = pytest.mark.asyncio |
861 | |
862 | -charm_build_dir = os.getenv('CHARM_BUILD_DIR', '..').rstrip('/') |
863 | +charm_build_dir = os.getenv("CHARM_BUILD_DIR", "..").rstrip("/") |
864 | |
865 | -series = [ |
866 | - 'focal', |
867 | - 'bionic', |
868 | - 'xenial', |
869 | -] |
870 | +series = ["focal", "bionic", "xenial"] |
871 | |
872 | -sources = [('local', '{}/builds/sysconfig'.format(charm_build_dir))] |
873 | +sources = [("local", "{}/builds/sysconfig".format(charm_build_dir))] |
874 | |
875 | TIMEOUT = 600 |
876 | MODEL_ACTIVE_TIMEOUT = 10 |
877 | -GRUB_DEFAULT = 'Advanced options for Ubuntu>Ubuntu, with Linux {}' |
878 | -PRINCIPAL_APP_NAME = 'ubuntu-{}' |
879 | +GRUB_DEFAULT = "Advanced options for Ubuntu>Ubuntu, with Linux {}" |
880 | +PRINCIPAL_APP_NAME = "ubuntu-{}" |
881 | |
882 | # Uncomment for re-using the current model, useful for debugging functional tests |
883 | # @pytest.fixture(scope='module') |
884 | @@ -54,39 +50,42 @@ def source(request): |
885 | @pytest.fixture |
886 | async def app(model, series, source): |
887 | """Return application of the charm under test.""" |
888 | - app_name = 'sysconfig-{}-{}'.format(series, source[0]) |
889 | - return await model._wait_for_new('application', app_name) |
890 | + app_name = "sysconfig-{}-{}".format(series, source[0]) |
891 | + return await model._wait_for_new("application", app_name) |
892 | |
893 | |
894 | # Tests |
895 | |
896 | + |
897 | async def test_sysconfig_deploy(model, series, source, request): |
898 | """Deploys the sysconfig charm as a subordinate of ubuntu.""" |
899 | - channel = 'stable' |
900 | - sysconfig_app_name = 'sysconfig-{}-{}'.format(series, source[0]) |
901 | + channel = "stable" |
902 | + sysconfig_app_name = "sysconfig-{}-{}".format(series, source[0]) |
903 | principal_app_name = PRINCIPAL_APP_NAME.format(series) |
904 | |
905 | ubuntu_app = await model.deploy( |
906 | - 'cs:ubuntu', |
907 | - application_name=principal_app_name, |
908 | - series=series, |
909 | - channel=channel, |
910 | + "cs:ubuntu", application_name=principal_app_name, series=series, channel=channel |
911 | ) |
912 | |
913 | - await model.block_until( |
914 | - lambda: ubuntu_app.status == 'active', |
915 | - timeout=TIMEOUT |
916 | - ) |
917 | + await model.block_until(lambda: ubuntu_app.status == "active", timeout=TIMEOUT) |
918 | |
919 | # Using subprocess b/c libjuju fails with JAAS |
920 | # https://github.com/juju/python-libjuju/issues/221 |
921 | - cmd = ['juju', 'deploy', source[1], '-m', model.info.name, |
922 | - '--series', series, sysconfig_app_name] |
923 | - |
924 | - if request.node.get_closest_marker('xfail'): |
925 | + cmd = [ |
926 | + "juju", |
927 | + "deploy", |
928 | + source[1], |
929 | + "-m", |
930 | + model.info.name, |
931 | + "--series", |
932 | + series, |
933 | + sysconfig_app_name, |
934 | + ] |
935 | + |
936 | + if request.node.get_closest_marker("xfail"): |
937 | # If series is 'xfail' force install to allow testing against versions not in |
938 | # metadata.yaml |
939 | - cmd.append('--force') |
940 | + cmd.append("--force") |
941 | subprocess.check_call(cmd) |
942 | |
943 | # This is pretty horrible, but we can't deploy via libjuju |
944 | @@ -97,145 +96,134 @@ async def test_sysconfig_deploy(model, series, source, request): |
945 | except KeyError: |
946 | await asyncio.sleep(5) |
947 | |
948 | - await sysconfig_app.add_relation('juju-info', '{}:juju-info'.format(principal_app_name)) |
949 | - |
950 | - await model.block_until( |
951 | - lambda: sysconfig_app.status == 'blocked', |
952 | - timeout=TIMEOUT |
953 | + await sysconfig_app.add_relation( |
954 | + "juju-info", "{}:juju-info".format(principal_app_name) |
955 | ) |
956 | |
957 | + await model.block_until(lambda: sysconfig_app.status == "blocked", timeout=TIMEOUT) |
958 | + |
959 | |
960 | async def test_cannot_run_in_container(app): |
961 | """Test that default config doesn't allow to install in container.""" |
962 | - assert app.status == 'blocked' |
963 | + assert app.status == "blocked" |
964 | |
965 | |
966 | async def test_forced_deploy(app, model): |
967 | """Force to install in container for testing purpose.""" |
968 | - await app.set_config({'enable-container': 'true'}) |
969 | - await model.block_until( |
970 | - lambda: app.status == 'active', |
971 | - timeout=TIMEOUT |
972 | - ) |
973 | - assert app.status == 'active' |
974 | + await app.set_config({"enable-container": "true"}) |
975 | + await model.block_until(lambda: app.status == "active", timeout=TIMEOUT) |
976 | + assert app.status == "active" |
977 | |
978 | |
979 | async def test_cpufrequtils_intalled(app, jujutools): |
980 | """Verify cpufrequtils pkg is installed.""" |
981 | unit = app.units[0] |
982 | - cmd = 'dpkg -l | grep cpufrequtils' |
983 | + cmd = "dpkg -l | grep cpufrequtils" |
984 | results = await jujutools.run_command(cmd, unit) |
985 | - assert results['Code'] == '0' |
986 | + assert results["Code"] == "0" |
987 | |
988 | |
989 | async def test_default_config(app, jujutools): |
990 | """Test default configuration for grub, systemd and cpufrequtils.""" |
991 | unit = app.units[0] |
992 | |
993 | - grup_path = '/etc/default/grub.d/90-sysconfig.cfg' |
994 | + grup_path = "/etc/default/grub.d/90-sysconfig.cfg" |
995 | grub_content = await jujutools.file_contents(grup_path, unit) |
996 | - assert 'isolcpus' not in grub_content |
997 | - assert 'hugepages' not in grub_content |
998 | - assert 'hugepagesz' not in grub_content |
999 | - assert 'raid' not in grub_content |
1000 | - assert 'pti=off' in grub_content |
1001 | - assert 'intel_iommu' not in grub_content |
1002 | - assert 'GRUB_DEFAULT' not in grub_content |
1003 | - |
1004 | - systemd_path = '/etc/systemd/system.conf' |
1005 | + assert "isolcpus" not in grub_content |
1006 | + assert "hugepages" not in grub_content |
1007 | + assert "hugepagesz" not in grub_content |
1008 | + assert "raid" not in grub_content |
1009 | + assert "pti=off" in grub_content |
1010 | + assert "intel_iommu" not in grub_content |
1011 | + assert "GRUB_DEFAULT" not in grub_content |
1012 | + |
1013 | + systemd_path = "/etc/systemd/system.conf" |
1014 | systemd_content = await jujutools.file_contents(systemd_path, unit) |
1015 | systemd_valid = True |
1016 | for line in systemd_content: |
1017 | - if line.startswith('CPUAffinity='): |
1018 | + if line.startswith("CPUAffinity="): |
1019 | systemd_valid = False |
1020 | assert systemd_valid |
1021 | |
1022 | - cpufreq_path = '/etc/default/cpufrequtils' |
1023 | + cpufreq_path = "/etc/default/cpufrequtils" |
1024 | cpufreq_content = await jujutools.file_contents(cpufreq_path, unit) |
1025 | - assert 'GOVERNOR' not in cpufreq_content |
1026 | + assert "GOVERNOR" not in cpufreq_content |
1027 | |
1028 | |
1029 | async def test_config_changed(app, model, jujutools): |
1030 | """Test configuration changed for grub, systemd, cpufrqutils and kernel.""" |
1031 | - kernel_version = '4.15.0-38-generic' |
1032 | - if 'focal' in app.entity_id: |
1033 | - # override the kernel_version for focal, we specify the oldest one ever released, as normal installations |
1034 | + kernel_version = "4.15.0-38-generic" |
1035 | + if "focal" in app.entity_id: |
1036 | + # override the kernel_version for focal, we specify the oldest one ever |
1037 | + # released, as normal installations |
1038 | # will updated to newest available |
1039 | - kernel_version = '5.4.0-29-generic' |
1040 | - linux_pkg = 'linux-image-{}'.format(kernel_version) |
1041 | - linux_modules_extra_pkg = 'linux-modules-extra-{}'.format(kernel_version) |
1042 | + kernel_version = "5.4.0-29-generic" |
1043 | + linux_pkg = "linux-image-{}".format(kernel_version) |
1044 | + linux_modules_extra_pkg = "linux-modules-extra-{}".format(kernel_version) |
1045 | |
1046 | await app.set_config( |
1047 | { |
1048 | - 'isolcpus': '1,2,3,4', |
1049 | - 'hugepages': '100', |
1050 | - 'hugepagesz': '1G', |
1051 | - 'raid-autodetection': 'noautodetect', |
1052 | - 'enable-pti': 'true', |
1053 | - 'enable-iommu': 'false', |
1054 | - 'kernel-version': kernel_version, |
1055 | - 'grub-config-flags': 'GRUB_TIMEOUT=10', |
1056 | - 'config-flags': '{"grub": "TEST=test"}', # config-flags are ignored when grub-config-flags are used |
1057 | - 'systemd-config-flags': 'LogLevel=warning,DumpCore=no', |
1058 | - 'governor': 'powersave' |
1059 | + "isolcpus": "1,2,3,4", |
1060 | + "hugepages": "100", |
1061 | + "hugepagesz": "1G", |
1062 | + "raid-autodetection": "noautodetect", |
1063 | + "enable-pti": "true", |
1064 | + "enable-iommu": "false", |
1065 | + "kernel-version": kernel_version, |
1066 | + "grub-config-flags": "GRUB_TIMEOUT=10", |
1067 | + # config-flags are ignored when grub-config-flags are used |
1068 | + "config-flags": '{"grub": "TEST=test"}', |
1069 | + "systemd-config-flags": "LogLevel=warning,DumpCore=no", |
1070 | + "governor": "powersave", |
1071 | } |
1072 | ) |
1073 | - await model.block_until( |
1074 | - lambda: app.status == 'active', |
1075 | - timeout=TIMEOUT |
1076 | - ) |
1077 | - assert app.status == 'active' |
1078 | + await model.block_until(lambda: app.status == "active", timeout=TIMEOUT) |
1079 | + assert app.status == "active" |
1080 | |
1081 | unit = app.units[0] |
1082 | |
1083 | - grup_path = '/etc/default/grub.d/90-sysconfig.cfg' |
1084 | + grup_path = "/etc/default/grub.d/90-sysconfig.cfg" |
1085 | grub_content = await jujutools.file_contents(grup_path, unit) |
1086 | - assert 'isolcpus=1,2,3,4' in grub_content |
1087 | - assert 'hugepages=100' in grub_content |
1088 | - assert 'hugepagesz=1G' in grub_content |
1089 | - assert 'raid=noautodetect' in grub_content |
1090 | - assert 'pti=off' not in grub_content |
1091 | - assert 'intel_iommu=on iommu=pt' not in grub_content |
1092 | - assert 'GRUB_DEFAULT="{}"'.format(GRUB_DEFAULT.format(kernel_version)) in grub_content |
1093 | - assert 'GRUB_TIMEOUT=10' in grub_content |
1094 | - assert 'TEST=test' not in grub_content |
1095 | + assert "isolcpus=1,2,3,4" in grub_content |
1096 | + assert "hugepages=100" in grub_content |
1097 | + assert "hugepagesz=1G" in grub_content |
1098 | + assert "raid=noautodetect" in grub_content |
1099 | + assert "pti=off" not in grub_content |
1100 | + assert "intel_iommu=on iommu=pt" not in grub_content |
1101 | + assert ( |
1102 | + 'GRUB_DEFAULT="{}"'.format(GRUB_DEFAULT.format(kernel_version)) in grub_content |
1103 | + ) |
1104 | + assert "GRUB_TIMEOUT=10" in grub_content |
1105 | + assert "TEST=test" not in grub_content |
1106 | |
1107 | # Reconfiguring reservation from isolcpus to affinity |
1108 | # isolcpus will be removed from grub and affinity added to systemd |
1109 | |
1110 | - await app.set_config( |
1111 | - { |
1112 | - 'isolcpus': '', |
1113 | - 'cpu-affinity-range': '1,2,3,4' |
1114 | - } |
1115 | - ) |
1116 | + await app.set_config({"isolcpus": "", "cpu-affinity-range": "1,2,3,4"}) |
1117 | |
1118 | - await model.block_until( |
1119 | - lambda: app.status == 'active', |
1120 | - timeout=TIMEOUT |
1121 | - ) |
1122 | - assert app.status == 'active' |
1123 | + await model.block_until(lambda: app.status == "active", timeout=TIMEOUT) |
1124 | + assert app.status == "active" |
1125 | |
1126 | - systemd_path = '/etc/systemd/system.conf' |
1127 | + systemd_path = "/etc/systemd/system.conf" |
1128 | systemd_content = await jujutools.file_contents(systemd_path, unit) |
1129 | |
1130 | - assert 'CPUAffinity=1,2,3,4' in systemd_content |
1131 | + assert "CPUAffinity=1,2,3,4" in systemd_content |
1132 | |
1133 | - assert 'LogLevel=warning' in systemd_content |
1134 | - assert 'DumpCore=no' in systemd_content |
1135 | + assert "LogLevel=warning" in systemd_content |
1136 | + assert "DumpCore=no" in systemd_content |
1137 | |
1138 | grub_content = await jujutools.file_contents(grup_path, unit) |
1139 | - assert 'isolcpus' not in grub_content |
1140 | + assert "isolcpus" not in grub_content |
1141 | |
1142 | - cpufreq_path = '/etc/default/cpufrequtils' |
1143 | + cpufreq_path = "/etc/default/cpufrequtils" |
1144 | cpufreq_content = await jujutools.file_contents(cpufreq_path, unit) |
1145 | - assert 'GOVERNOR=powersave' in cpufreq_content |
1146 | + assert "GOVERNOR=powersave" in cpufreq_content |
1147 | |
1148 | # test new kernel installed |
1149 | for pkg in (linux_pkg, linux_modules_extra_pkg): |
1150 | - cmd = 'dpkg -l | grep {}'.format(pkg) |
1151 | + cmd = "dpkg -l | grep {}".format(pkg) |
1152 | results = await jujutools.run_command(cmd, unit) |
1153 | - assert results['Code'] == '0' |
1154 | + assert results["Code"] == "0" |
1155 | |
1156 | # test update-status show that reboot is required |
1157 | assert "reboot required." in unit.workload_status_message |
1158 | @@ -244,9 +232,9 @@ async def test_config_changed(app, model, jujutools): |
1159 | async def test_clear_notification(app): |
1160 | """Tests that clear-notification action complete.""" |
1161 | unit = app.units[0] |
1162 | - action = await unit.run_action('clear-notification') |
1163 | + action = await unit.run_action("clear-notification") |
1164 | action = await action.wait() |
1165 | - assert action.status == 'completed' |
1166 | + assert action.status == "completed" |
1167 | |
1168 | |
1169 | # This may need to be removed at some point once the reservation |
1170 | @@ -256,81 +244,58 @@ async def test_wrong_reservation(app, model): |
1171 | |
1172 | Expect application is blocked until correct value is set. |
1173 | """ |
1174 | - await app.set_config( |
1175 | - { |
1176 | - 'reservation': 'changeme' |
1177 | - } |
1178 | - ) |
1179 | - await model.block_until( |
1180 | - lambda: app.status == 'blocked', |
1181 | - timeout=TIMEOUT |
1182 | - ) |
1183 | - assert app.status == 'blocked' |
1184 | + await app.set_config({"reservation": "changeme"}) |
1185 | + await model.block_until(lambda: app.status == "blocked", timeout=TIMEOUT) |
1186 | + assert app.status == "blocked" |
1187 | unit = app.units[0] |
1188 | - assert 'configuration parameters not valid.' in unit.workload_status_message |
1189 | + assert "configuration parameters not valid." in unit.workload_status_message |
1190 | |
1191 | - await app.set_config( |
1192 | - { |
1193 | - 'reservation': 'off' |
1194 | - } |
1195 | - ) |
1196 | - await model.block_until( |
1197 | - lambda: app.status == 'active', |
1198 | - timeout=TIMEOUT |
1199 | - ) |
1200 | + await app.set_config({"reservation": "off"}) |
1201 | + await model.block_until(lambda: app.status == "active", timeout=TIMEOUT) |
1202 | |
1203 | |
1204 | -@pytest.mark.parametrize('key,bad_value,good_value', [ |
1205 | - ('raid-autodetection', 'changeme', ''), |
1206 | - ('governor', 'changeme', ''), |
1207 | - ('resolved-cache-mode', 'changeme', ''), |
1208 | -]) |
1209 | +@pytest.mark.parametrize( |
1210 | + "key,bad_value,good_value", |
1211 | + [ |
1212 | + ("raid-autodetection", "changeme", ""), |
1213 | + ("governor", "changeme", ""), |
1214 | + ("resolved-cache-mode", "changeme", ""), |
1215 | + ], |
1216 | +) |
1217 | async def test_invalid_configuration_parameters(app, model, key, bad_value, good_value): |
1218 | """Tests wrong config value is used. |
1219 | |
1220 | Expect application is blocked until correct value is set. |
1221 | """ |
1222 | - await app.set_config( |
1223 | - { |
1224 | - key: bad_value |
1225 | - } |
1226 | - ) |
1227 | - await model.block_until( |
1228 | - lambda: app.status == 'blocked', |
1229 | - timeout=TIMEOUT |
1230 | - ) |
1231 | - assert app.status == 'blocked' |
1232 | + await app.set_config({key: bad_value}) |
1233 | + await model.block_until(lambda: app.status == "blocked", timeout=TIMEOUT) |
1234 | + assert app.status == "blocked" |
1235 | unit = app.units[0] |
1236 | - assert 'configuration parameters not valid.' in unit.workload_status_message |
1237 | + assert "configuration parameters not valid." in unit.workload_status_message |
1238 | |
1239 | - await app.set_config( |
1240 | - { |
1241 | - key: good_value |
1242 | - } |
1243 | - ) |
1244 | - await model.block_until( |
1245 | - lambda: app.status == 'active', |
1246 | - timeout=TIMEOUT |
1247 | - ) |
1248 | + await app.set_config({key: good_value}) |
1249 | + await model.block_until(lambda: app.status == "active", timeout=TIMEOUT) |
1250 | |
1251 | |
1252 | -@pytest.mark.parametrize('cache_setting', [ |
1253 | - 'yes', |
1254 | - 'no', |
1255 | - 'no-negative', |
1256 | -]) |
1257 | +@pytest.mark.parametrize("cache_setting", ["yes", "no", "no-negative"]) |
1258 | async def test_set_resolved_cache(app, model, jujutools, cache_setting): |
1259 | """Tests resolved cache settings.""" |
1260 | + |
1261 | def is_model_settled(): |
1262 | - return app.units[0].workload_status == 'active' and app.units[0].agent_status == 'idle' |
1263 | + return ( |
1264 | + app.units[0].workload_status == "active" |
1265 | + and app.units[0].agent_status == "idle" # noqa: W503 |
1266 | + ) |
1267 | |
1268 | await model.block_until(is_model_settled, timeout=TIMEOUT) |
1269 | |
1270 | - await app.set_config({'resolved-cache-mode': cache_setting}) |
1271 | + await app.set_config({"resolved-cache-mode": cache_setting}) |
1272 | # NOTE: app.set_config() doesn't seem to wait for the model to go to a |
1273 | # non-active/idle state. |
1274 | try: |
1275 | - await model.block_until(lambda: not is_model_settled(), timeout=MODEL_ACTIVE_TIMEOUT) |
1276 | + await model.block_until( |
1277 | + lambda: not is_model_settled(), timeout=MODEL_ACTIVE_TIMEOUT |
1278 | + ) |
1279 | except websockets.ConnectionClosed: |
1280 | # It's possible (although unlikely) that we missed the charm transitioning from |
1281 | # idle to active and back. |
1282 | @@ -338,36 +303,42 @@ async def test_set_resolved_cache(app, model, jujutools, cache_setting): |
1283 | |
1284 | await model.block_until(is_model_settled, timeout=TIMEOUT) |
1285 | |
1286 | - resolved_conf_content = await jujutools.file_contents('/etc/systemd/resolved.conf', app.units[0]) |
1287 | - assert re.search('^Cache={}$'.format(cache_setting), resolved_conf_content, re.MULTILINE) |
1288 | + resolved_conf_content = await jujutools.file_contents( |
1289 | + "/etc/systemd/resolved.conf", app.units[0] |
1290 | + ) |
1291 | + assert re.search( |
1292 | + "^Cache={}$".format(cache_setting), resolved_conf_content, re.MULTILINE |
1293 | + ) |
1294 | |
1295 | |
1296 | -@pytest.mark.parametrize('sysctl', ['1', '0']) |
1297 | +@pytest.mark.parametrize("sysctl", ["1", "0"]) |
1298 | async def test_set_sysctl(app, model, jujutools, sysctl): |
1299 | """Tests sysctl settings.""" |
1300 | + |
1301 | def is_model_settled(): |
1302 | - return app.units[0].workload_status == 'active' and app.units[0].agent_status == 'idle' |
1303 | + return ( |
1304 | + app.units[0].workload_status == "active" |
1305 | + and app.units[0].agent_status == "idle" # noqa: W503 |
1306 | + ) |
1307 | |
1308 | await model.block_until(is_model_settled, timeout=TIMEOUT) |
1309 | |
1310 | - await app.set_config({ |
1311 | - 'sysctl': "net.ipv4.ip_forward: %s" % sysctl |
1312 | - }) |
1313 | + await app.set_config({"sysctl": "net.ipv4.ip_forward: %s" % sysctl}) |
1314 | # NOTE: app.set_config() doesn't seem to wait for the model to go to a |
1315 | # non-active/idle state. |
1316 | try: |
1317 | - await model.block_until(lambda: not is_model_settled(), timeout=MODEL_ACTIVE_TIMEOUT) |
1318 | + await model.block_until( |
1319 | + lambda: not is_model_settled(), timeout=MODEL_ACTIVE_TIMEOUT |
1320 | + ) |
1321 | except websockets.ConnectionClosed: |
1322 | # It's possible (although unlikely) that we missed the charm transitioning from |
1323 | # idle to active and back. |
1324 | pass |
1325 | |
1326 | await model.block_until(is_model_settled, timeout=TIMEOUT) |
1327 | - result = await jujutools.run_command('sysctl -a', app.units[0]) |
1328 | - content = result['Stdout'] |
1329 | - assert re.search( |
1330 | - '^net.ipv4.ip_forward = {}$'.format(sysctl), content, re.MULTILINE |
1331 | - ) |
1332 | + result = await jujutools.run_command("sysctl -a", app.units[0]) |
1333 | + content = result["Stdout"] |
1334 | + assert re.search("^net.ipv4.ip_forward = {}$".format(sysctl), content, re.MULTILINE) |
1335 | |
1336 | |
1337 | async def test_uninstall(app, model, jujutools, series): |
1338 | @@ -376,42 +347,36 @@ async def test_uninstall(app, model, jujutools, series): |
1339 | # after removing the relation with ubuntu |
1340 | await app.set_config( |
1341 | { |
1342 | - 'reservation': 'affinity', |
1343 | - 'cpu-range': '1,2,3,4', |
1344 | - 'governor': 'performance', |
1345 | - 'raid-autodetection': '' |
1346 | + "reservation": "affinity", |
1347 | + "cpu-range": "1,2,3,4", |
1348 | + "governor": "performance", |
1349 | + "raid-autodetection": "", |
1350 | } |
1351 | ) |
1352 | |
1353 | - await model.block_until( |
1354 | - lambda: app.status == 'active', |
1355 | - timeout=TIMEOUT |
1356 | - ) |
1357 | + await model.block_until(lambda: app.status == "active", timeout=TIMEOUT) |
1358 | |
1359 | principal_app_name = PRINCIPAL_APP_NAME.format(series) |
1360 | principal_app = model.applications[principal_app_name] |
1361 | |
1362 | - await app.destroy_relation('juju-info', '{}:juju-info'.format(principal_app_name)) |
1363 | + await app.destroy_relation("juju-info", "{}:juju-info".format(principal_app_name)) |
1364 | |
1365 | - await model.block_until( |
1366 | - lambda: len(app.units) == 0, |
1367 | - timeout=TIMEOUT |
1368 | - ) |
1369 | + await model.block_until(lambda: len(app.units) == 0, timeout=TIMEOUT) |
1370 | |
1371 | unit = principal_app.units[0] |
1372 | - grup_path = '/etc/default/grub.d/90-sysconfig.cfg' |
1373 | - cmd = 'cat {}'.format(grup_path) |
1374 | + grup_path = "/etc/default/grub.d/90-sysconfig.cfg" |
1375 | + cmd = "cat {}".format(grup_path) |
1376 | results = await jujutools.run_command(cmd, unit) |
1377 | - assert results['Code'] != '0' |
1378 | + assert results["Code"] != "0" |
1379 | |
1380 | - systemd_path = '/etc/systemd/system.conf' |
1381 | + systemd_path = "/etc/systemd/system.conf" |
1382 | systemd_content = await jujutools.file_contents(systemd_path, unit) |
1383 | - assert 'CPUAffinity=1,2,3,4' not in systemd_content |
1384 | + assert "CPUAffinity=1,2,3,4" not in systemd_content |
1385 | |
1386 | - resolved_path = '/etc/systemd/resolved.conf' |
1387 | + resolved_path = "/etc/systemd/resolved.conf" |
1388 | resolved_content = await jujutools.file_contents(resolved_path, unit) |
1389 | - assert not re.search('^Cache=', resolved_content, re.MULTILINE) |
1390 | + assert not re.search("^Cache=", resolved_content, re.MULTILINE) |
1391 | |
1392 | - cpufreq_path = '/etc/default/cpufrequtils' |
1393 | + cpufreq_path = "/etc/default/cpufrequtils" |
1394 | cpufreq_content = await jujutools.file_contents(cpufreq_path, unit) |
1395 | - assert 'GOVERNOR' not in cpufreq_content |
1396 | + assert "GOVERNOR" not in cpufreq_content |
1397 | diff --git a/src/tests/unit/conftest.py b/src/tests/unit/conftest.py |
1398 | index 50dd26e..7a94633 100644 |
1399 | --- a/src/tests/unit/conftest.py |
1400 | +++ b/src/tests/unit/conftest.py |
1401 | @@ -9,19 +9,20 @@ import pytest |
1402 | @pytest.fixture |
1403 | def mock_layers(monkeypatch): |
1404 | import sys |
1405 | - sys.modules['charms.layer'] = mock.Mock() |
1406 | - sys.modules['reactive'] = mock.Mock() |
1407 | + |
1408 | + sys.modules["charms.layer"] = mock.Mock() |
1409 | + sys.modules["reactive"] = mock.Mock() |
1410 | # Mock any functions in layers that need to be mocked here |
1411 | |
1412 | def options(layer): |
1413 | # mock options for layers here |
1414 | - if layer == 'example-layer': |
1415 | - options = {'port': 9999} |
1416 | + if layer == "example-layer": |
1417 | + options = {"port": 9999} |
1418 | return options |
1419 | else: |
1420 | return None |
1421 | |
1422 | - monkeypatch.setattr('lib_sysconfig.layer.options', options) |
1423 | + monkeypatch.setattr("lib_sysconfig.layer.options", options) |
1424 | |
1425 | |
1426 | @pytest.fixture |
1427 | @@ -30,35 +31,36 @@ def mock_hookenv_config(monkeypatch): |
1428 | |
1429 | def mock_config(): |
1430 | cfg = {} |
1431 | - yml = yaml.load(open('./config.yaml')) |
1432 | + yml = yaml.load(open("./config.yaml")) |
1433 | |
1434 | # Load all defaults |
1435 | - for key, value in yml['options'].items(): |
1436 | - cfg[key] = value['default'] |
1437 | + for key, value in yml["options"].items(): |
1438 | + cfg[key] = value["default"] |
1439 | |
1440 | # Manually add cfg from other layers |
1441 | # cfg['my-other-layer'] = 'mock' |
1442 | return cfg |
1443 | |
1444 | - monkeypatch.setattr('lib_sysconfig.hookenv.config', mock_config) |
1445 | + monkeypatch.setattr("lib_sysconfig.hookenv.config", mock_config) |
1446 | |
1447 | |
1448 | @pytest.fixture |
1449 | def mock_remote_unit(monkeypatch): |
1450 | - monkeypatch.setattr('lib_sysconfig.hookenv.remote_unit', lambda: 'unit-mock/0') |
1451 | + monkeypatch.setattr("lib_sysconfig.hookenv.remote_unit", lambda: "unit-mock/0") |
1452 | |
1453 | |
1454 | @pytest.fixture |
1455 | def mock_charm_dir(monkeypatch): |
1456 | - monkeypatch.setattr('lib_sysconfig.hookenv.charm_dir', lambda: '/mock/charm/dir') |
1457 | + monkeypatch.setattr("lib_sysconfig.hookenv.charm_dir", lambda: "/mock/charm/dir") |
1458 | |
1459 | |
1460 | @pytest.fixture |
1461 | def sysconfig(tmpdir, mock_hookenv_config, mock_charm_dir, monkeypatch): |
1462 | from lib_sysconfig import SysConfigHelper |
1463 | + |
1464 | helper = SysConfigHelper() |
1465 | |
1466 | # Any other functions that load helper will get this version |
1467 | - monkeypatch.setattr('lib_sysconfig.SysConfigHelper', lambda: helper) |
1468 | + monkeypatch.setattr("lib_sysconfig.SysConfigHelper", lambda: helper) |
1469 | |
1470 | return helper |
1471 | diff --git a/src/tests/unit/test_lib.py b/src/tests/unit/test_lib.py |
1472 | index 72d8b70..df93a76 100644 |
1473 | --- a/src/tests/unit/test_lib.py |
1474 | +++ b/src/tests/unit/test_lib.py |
1475 | @@ -86,8 +86,9 @@ class TestBootResourceState: |
1476 | mock_boot_time.return_value = self.datetime - timedelta(1) |
1477 | boot_resource = self.boot_resource() |
1478 | with NamedTemporaryFile() as ftmp: |
1479 | - with mock.patch.object(boot_resource, |
1480 | - 'calculate_resource_sha256sum') as mock_calc: |
1481 | + with mock.patch.object( |
1482 | + boot_resource, "calculate_resource_sha256sum" |
1483 | + ) as mock_calc: |
1484 | mock_calc.return_value = "1234" |
1485 | changed = boot_resource.resources_changed_since_boot([ftmp.name]) |
1486 | assert not changed |
1487 | @@ -98,8 +99,9 @@ class TestBootResourceState: |
1488 | mock_boot_time.return_value = self.datetime - timedelta(1) |
1489 | boot_resource = self.boot_resource() |
1490 | with NamedTemporaryFile() as ftmp: |
1491 | - with mock.patch.object(boot_resource, |
1492 | - 'calculate_resource_sha256sum') as mock_calc: |
1493 | + with mock.patch.object( |
1494 | + boot_resource, "calculate_resource_sha256sum" |
1495 | + ) as mock_calc: |
1496 | mock_calc.return_value = "2345" |
1497 | changed = boot_resource.resources_changed_since_boot([ftmp.name]) |
1498 | assert changed |
1499 | @@ -137,8 +139,10 @@ class TestLib: |
1500 | context=expected, |
1501 | ) |
1502 | check_call.assert_called_with( |
1503 | - ['/bin/systemctl', 'mask', 'ondemand'], |
1504 | - stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) |
1505 | + ["/bin/systemctl", "mask", "ondemand"], |
1506 | + stdout=subprocess.DEVNULL, |
1507 | + stderr=subprocess.DEVNULL, |
1508 | + ) |
1509 | |
1510 | @mock.patch("lib_sysconfig.subprocess.call") |
1511 | @mock.patch("lib_sysconfig.hookenv.config") |
1512 | @@ -162,14 +166,18 @@ class TestLib: |
1513 | ) |
1514 | restart.assert_called() |
1515 | check_call.assert_called_with( |
1516 | - ['/bin/systemctl', 'unmask', 'ondemand'], |
1517 | - stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) |
1518 | + ["/bin/systemctl", "unmask", "ondemand"], |
1519 | + stdout=subprocess.DEVNULL, |
1520 | + stderr=subprocess.DEVNULL, |
1521 | + ) |
1522 | |
1523 | @mock.patch("lib_sysconfig.subprocess.call") |
1524 | @mock.patch("lib_sysconfig.hookenv.config") |
1525 | @mock.patch("lib_sysconfig.host.service_restart") |
1526 | @mock.patch("lib_sysconfig.render") |
1527 | - def test_update_cpufreq_governor_not_available(self, render, restart, config, check_call): |
1528 | + def test_update_cpufreq_governor_not_available( |
1529 | + self, render, restart, config, check_call |
1530 | + ): |
1531 | """Set wrong governor. |
1532 | |
1533 | Expect /etc/default/cpufrequtils is not rendered |
1534 | @@ -199,9 +207,9 @@ class TestLib: |
1535 | "raid-autodetection": "noautodetect", |
1536 | "enable-pti": True, |
1537 | "enable-iommu": True, |
1538 | - "grub-config-flags": "TEST_KEY=\"TEST VALUE, WITH COMMA\", GRUB_TIMEOUT=0", |
1539 | + "grub-config-flags": 'TEST_KEY="TEST VALUE, WITH COMMA", GRUB_TIMEOUT=0', |
1540 | "kernel-version": "4.15.0-38-generic", |
1541 | - "update-grub": True |
1542 | + "update-grub": True, |
1543 | } |
1544 | |
1545 | expected = { |
1546 | @@ -210,8 +218,12 @@ class TestLib: |
1547 | "hugepagesz": "1G", |
1548 | "raid": "noautodetect", |
1549 | "iommu": True, |
1550 | - "grub_config_flags": {"GRUB_TIMEOUT": "0", "TEST_KEY": "\"TEST VALUE, WITH COMMA\""}, |
1551 | - "grub_default": "Advanced options for Ubuntu>Ubuntu, with Linux 4.15.0-38-generic" |
1552 | + "grub_config_flags": { |
1553 | + "GRUB_TIMEOUT": "0", |
1554 | + "TEST_KEY": '"TEST VALUE, WITH COMMA"', |
1555 | + }, |
1556 | + "grub_default": "Advanced options for Ubuntu>Ubuntu, " |
1557 | + "with Linux 4.15.0-38-generic", |
1558 | } |
1559 | |
1560 | sysh = lib_sysconfig.SysConfigHelper() |
1561 | @@ -241,9 +253,9 @@ class TestLib: |
1562 | "raid-autodetection": "noautodetect", |
1563 | "enable-pti": True, |
1564 | "enable-iommu": True, |
1565 | - "grub-config-flags": "TEST_KEY=\"TEST VALUE, WITH COMMA\", GRUB_TIMEOUT=0", |
1566 | + "grub-config-flags": 'TEST_KEY="TEST VALUE, WITH COMMA", GRUB_TIMEOUT=0', |
1567 | "kernel-version": "4.15.0-38-generic", |
1568 | - "update-grub": True |
1569 | + "update-grub": True, |
1570 | } |
1571 | |
1572 | expected = { |
1573 | @@ -252,8 +264,12 @@ class TestLib: |
1574 | "hugepagesz": "1G", |
1575 | "raid": "noautodetect", |
1576 | "iommu": True, |
1577 | - "grub_config_flags": {"GRUB_TIMEOUT": "0", "TEST_KEY": "\"TEST VALUE, WITH COMMA\""}, |
1578 | - "grub_default": "Advanced options for Ubuntu>Ubuntu, with Linux 4.15.0-38-generic" |
1579 | + "grub_config_flags": { |
1580 | + "GRUB_TIMEOUT": "0", |
1581 | + "TEST_KEY": '"TEST VALUE, WITH COMMA"', |
1582 | + }, |
1583 | + "grub_default": "Advanced options for Ubuntu>Ubuntu, " |
1584 | + "with Linux 4.15.0-38-generic", |
1585 | } |
1586 | |
1587 | sysh = lib_sysconfig.SysConfigHelper() |
1588 | @@ -283,14 +299,18 @@ class TestLib: |
1589 | "raid-autodetection": "", |
1590 | "enable-pti": True, |
1591 | "enable-iommu": False, |
1592 | - "config-flags": "{ 'grub': 'GRUB_TIMEOUT=0, TEST=line with space, and comma'}", |
1593 | + "config-flags": "{ 'grub': 'GRUB_TIMEOUT=0, " |
1594 | + "TEST=line with space, and comma'}", |
1595 | "grub-config-flags": "", |
1596 | "kernel-version": "", |
1597 | "update-grub": True, |
1598 | } |
1599 | |
1600 | expected = { |
1601 | - "grub_config_flags": {"GRUB_TIMEOUT": "0", "TEST": "line with space, and comma"}, |
1602 | + "grub_config_flags": { |
1603 | + "GRUB_TIMEOUT": "0", |
1604 | + "TEST": "line with space, and comma", |
1605 | + } |
1606 | } |
1607 | |
1608 | sysh = lib_sysconfig.SysConfigHelper() |
1609 | @@ -320,9 +340,9 @@ class TestLib: |
1610 | "raid-autodetection": "noautodetect", |
1611 | "enable-pti": False, |
1612 | "enable-iommu": True, |
1613 | - "grub-config-flags": "GRUB_TIMEOUT=0, TEST=\"one,two,three, four\"", |
1614 | + "grub-config-flags": 'GRUB_TIMEOUT=0, TEST="one,two,three, four"', |
1615 | "kernel-version": "4.15.0-38-generic", |
1616 | - "update-grub": False |
1617 | + "update-grub": False, |
1618 | } |
1619 | |
1620 | expected = { |
1621 | @@ -331,9 +351,10 @@ class TestLib: |
1622 | "hugepagesz": "1G", |
1623 | "raid": "noautodetect", |
1624 | "iommu": True, |
1625 | - "grub_config_flags": {"GRUB_TIMEOUT": "0", "TEST": "\"one,two,three, four\""}, |
1626 | - "grub_default": "Advanced options for Ubuntu>Ubuntu, with Linux 4.15.0-38-generic", |
1627 | - 'pti_off': True |
1628 | + "grub_config_flags": {"GRUB_TIMEOUT": "0", "TEST": '"one,two,three, four"'}, |
1629 | + "grub_default": "Advanced options for Ubuntu>Ubuntu, " |
1630 | + "with Linux 4.15.0-38-generic", |
1631 | + "pti_off": True, |
1632 | } |
1633 | |
1634 | sysh = lib_sysconfig.SysConfigHelper() |
1635 | @@ -357,15 +378,15 @@ class TestLib: |
1636 | config.return_value = { |
1637 | "reservation": "off", |
1638 | "cpu-affinity-range": "0-10", |
1639 | - "systemd-config-flags": "DefaultLimitRTTIME=1,DefaultTasksMax=10" |
1640 | + "systemd-config-flags": "DefaultLimitRTTIME=1,DefaultTasksMax=10", |
1641 | } |
1642 | |
1643 | expected = { |
1644 | "cpu_affinity_range": "0-10", |
1645 | "systemd_config_flags": { |
1646 | "DefaultLimitRTTIME": "1", |
1647 | - "DefaultTasksMax": "10" |
1648 | - } |
1649 | + "DefaultTasksMax": "10", |
1650 | + }, |
1651 | } |
1652 | |
1653 | sysh = lib_sysconfig.SysConfigHelper() |
1654 | @@ -388,15 +409,15 @@ class TestLib: |
1655 | config.return_value = { |
1656 | "reservation": "affinity", |
1657 | "cpu-range": "0-10", |
1658 | - "systemd-config-flags": "DefaultLimitRTTIME=1,DefaultTasksMax=10" |
1659 | + "systemd-config-flags": "DefaultLimitRTTIME=1,DefaultTasksMax=10", |
1660 | } |
1661 | |
1662 | expected = { |
1663 | "cpu_affinity_range": "0-10", |
1664 | "systemd_config_flags": { |
1665 | "DefaultLimitRTTIME": "1", |
1666 | - "DefaultTasksMax": "10" |
1667 | - } |
1668 | + "DefaultTasksMax": "10", |
1669 | + }, |
1670 | } |
1671 | |
1672 | sysh = lib_sysconfig.SysConfigHelper() |
1673 | @@ -420,15 +441,15 @@ class TestLib: |
1674 | "reservation": "off", |
1675 | "cpu-affinity-range": "0-10", |
1676 | "config-flags": "{'systemd': 'DefaultLimitRTTIME=1, DefaultTasksMax=10'}", |
1677 | - "systemd-config-flags": "" |
1678 | + "systemd-config-flags": "", |
1679 | } |
1680 | |
1681 | expected = { |
1682 | "cpu_affinity_range": "0-10", |
1683 | "systemd_config_flags": { |
1684 | "DefaultLimitRTTIME": "1", |
1685 | - "DefaultTasksMax": "10" |
1686 | - } |
1687 | + "DefaultTasksMax": "10", |
1688 | + }, |
1689 | } |
1690 | |
1691 | sysh = lib_sysconfig.SysConfigHelper() |
1692 | @@ -445,21 +466,24 @@ class TestLib: |
1693 | @mock.patch("lib_sysconfig.hookenv.config") |
1694 | @mock.patch("lib_sysconfig.running_kernel") |
1695 | @mock.patch("lib_sysconfig.hookenv.log") |
1696 | - def test_install_configured_kernel_true(self, log, running_kernel, config, apt_update, apt_install): |
1697 | + def test_install_configured_kernel_true( |
1698 | + self, log, running_kernel, config, apt_update, apt_install |
1699 | + ): |
1700 | """Set config kernel=4.15.0-38-generic and running kernel is different. |
1701 | |
1702 | Expect apt install is called. |
1703 | """ |
1704 | - config.return_value = { |
1705 | - "kernel-version": "4.15.0-38-generic" |
1706 | - } |
1707 | + config.return_value = {"kernel-version": "4.15.0-38-generic"} |
1708 | |
1709 | running_kernel.return_value = "4.4.0-38-generic" |
1710 | sysh = lib_sysconfig.SysConfigHelper() |
1711 | sysh.install_configured_kernel() |
1712 | |
1713 | apt_install.assert_called_with( |
1714 | - ["linux-image-{}".format("4.15.0-38-generic"), "linux-modules-extra-{}".format("4.15.0-38-generic")] |
1715 | + [ |
1716 | + "linux-image-{}".format("4.15.0-38-generic"), |
1717 | + "linux-modules-extra-{}".format("4.15.0-38-generic"), |
1718 | + ] |
1719 | ) |
1720 | |
1721 | @mock.patch("lib_sysconfig.apt_install") |
1722 | @@ -467,15 +491,15 @@ class TestLib: |
1723 | @mock.patch("lib_sysconfig.hookenv.config") |
1724 | @mock.patch("lib_sysconfig.running_kernel") |
1725 | @mock.patch("lib_sysconfig.hookenv.log") |
1726 | - def test_install_configured_kernel_false(self, log, running_kernel, config, apt_update, apt_install): |
1727 | + def test_install_configured_kernel_false( |
1728 | + self, log, running_kernel, config, apt_update, apt_install |
1729 | + ): |
1730 | """Set config kernel=4.15.0-38-generic and running kernel is the same. |
1731 | |
1732 | Expect apt install is not called. |
1733 | """ |
1734 | kernel_version = "4.15.0-38-generic" |
1735 | - config.return_value = { |
1736 | - "kernel-version": kernel_version |
1737 | - } |
1738 | + config.return_value = {"kernel-version": kernel_version} |
1739 | |
1740 | running_kernel.return_value = "4.15.0-38-generic" |
1741 | sysh = lib_sysconfig.SysConfigHelper() |
1742 | @@ -488,14 +512,14 @@ class TestLib: |
1743 | @mock.patch("lib_sysconfig.hookenv.config") |
1744 | @mock.patch("lib_sysconfig.running_kernel") |
1745 | @mock.patch("lib_sysconfig.hookenv.log") |
1746 | - def test_install_configured_kernel_no_specified(self, log, running_kernel, config, apt_update, apt_install): |
1747 | + def test_install_configured_kernel_no_specified( |
1748 | + self, log, running_kernel, config, apt_update, apt_install |
1749 | + ): |
1750 | """Set config kernel=''. |
1751 | |
1752 | Expect apt install is not called. |
1753 | """ |
1754 | - config.return_value = { |
1755 | - "kernel-version": "" |
1756 | - } |
1757 | + config.return_value = {"kernel-version": ""} |
1758 | |
1759 | running_kernel.return_value = "4.15.0-38-generic" |
1760 | sysh = lib_sysconfig.SysConfigHelper() |
1761 | @@ -512,9 +536,7 @@ class TestLib: |
1762 | |
1763 | Expect os.remove is called |
1764 | """ |
1765 | - config.return_value = { |
1766 | - "update-grub": False |
1767 | - } |
1768 | + config.return_value = {"update-grub": False} |
1769 | exists.return_value = True |
1770 | |
1771 | with NamedTemporaryFile() as ftmp: |
1772 | @@ -532,9 +554,7 @@ class TestLib: |
1773 | |
1774 | Expect os.remove is not called |
1775 | """ |
1776 | - config.return_value = { |
1777 | - "update-grub": False |
1778 | - } |
1779 | + config.return_value = {"update-grub": False} |
1780 | exists.return_value = False |
1781 | |
1782 | sysh = lib_sysconfig.SysConfigHelper() |
1783 | @@ -557,7 +577,7 @@ class TestLib: |
1784 | source=lib_sysconfig.SYSTEMD_SYSTEM_TMPL, |
1785 | target=lib_sysconfig.SYSTEMD_SYSTEM, |
1786 | templates_dir="templates", |
1787 | - context={} |
1788 | + context={}, |
1789 | ) |
1790 | |
1791 | @mock.patch("lib_sysconfig.hookenv.config") |
1792 | @@ -565,7 +585,9 @@ class TestLib: |
1793 | @mock.patch("lib_sysconfig.host.service_restart") |
1794 | @mock.patch("lib_sysconfig.subprocess.call") |
1795 | @mock.patch("lib_sysconfig.hookenv.log") |
1796 | - def test_remove_cpufreq_configuration_xenial(self, log, check_call, restart, render, config): |
1797 | + def test_remove_cpufreq_configuration_xenial( |
1798 | + self, log, check_call, restart, render, config |
1799 | + ): |
1800 | """Test remove cpufrequtlis configuration. |
1801 | |
1802 | Expect config is rendered with empty context. |
1803 | @@ -574,18 +596,22 @@ class TestLib: |
1804 | sysh.remove_cpufreq_configuration() |
1805 | |
1806 | check_call.assert_called_with( |
1807 | - ['/bin/systemctl', 'unmask', 'ondemand'], |
1808 | - stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) |
1809 | + ["/bin/systemctl", "unmask", "ondemand"], |
1810 | + stdout=subprocess.DEVNULL, |
1811 | + stderr=subprocess.DEVNULL, |
1812 | + ) |
1813 | render.assert_called_with( |
1814 | source=lib_sysconfig.CPUFREQUTILS_TMPL, |
1815 | target=lib_sysconfig.CPUFREQUTILS, |
1816 | templates_dir="templates", |
1817 | - context={} |
1818 | + context={}, |
1819 | ) |
1820 | restart.assert_called() |
1821 | |
1822 | - @pytest.mark.parametrize("invalid_config_key", [ |
1823 | - "reservation", "raid-autodetection", "governor", "resolved-cache-mode"]) |
1824 | + @pytest.mark.parametrize( |
1825 | + "invalid_config_key", |
1826 | + ["reservation", "raid-autodetection", "governor", "resolved-cache-mode"], |
1827 | + ) |
1828 | @mock.patch("lib_sysconfig.hookenv.config") |
1829 | def test_wrong_config(self, config, invalid_config_key): |
1830 | """Test wrong configuration value. |
1831 | @@ -597,7 +623,7 @@ class TestLib: |
1832 | "raid-autodetection": "", |
1833 | "governor": "", |
1834 | "resolved-cache-mode": "", |
1835 | - invalid_config_key: 'wrong', # Will override the selected key with an invalid value |
1836 | + invalid_config_key: "wrong", # Will override key with an invalid value |
1837 | } |
1838 | config.return_value = return_value |
1839 | sysh = lib_sysconfig.SysConfigHelper() |
1840 | @@ -606,9 +632,7 @@ class TestLib: |
1841 | @mock.patch("lib_sysconfig.hookenv.config") |
1842 | def test_enable_container(self, config): |
1843 | """Test enable container.""" |
1844 | - config.return_value = { |
1845 | - "enable-container": True |
1846 | - } |
1847 | + config.return_value = {"enable-container": True} |
1848 | sysh = lib_sysconfig.SysConfigHelper() |
1849 | |
1850 | assert sysh.enable_container |
1851 | @@ -617,7 +641,9 @@ class TestLib: |
1852 | @mock.patch("lib_sysconfig.hookenv.config") |
1853 | @mock.patch("lib_sysconfig.host.service_restart") |
1854 | @mock.patch("lib_sysconfig.render") |
1855 | - def test_update_resolved_file_unchanged(self, render, restart, config, file_changed): |
1856 | + def test_update_resolved_file_unchanged( |
1857 | + self, render, restart, config, file_changed |
1858 | + ): |
1859 | """systemd-resolved is not restarted when the config file is unchanged.""" |
1860 | file_changed.return_value = False |
1861 | self._test_update_resolved_common(render, config) |
1862 | @@ -658,15 +684,12 @@ class TestLib: |
1863 | with mock.patch("builtins.open", mock.mock_open()) as mock_file: |
1864 | sysh.update_sysctl() |
1865 | |
1866 | - mock_file.assert_called_with(lib_sysconfig.SYSCTL_CONF, 'w') |
1867 | + mock_file.assert_called_with(lib_sysconfig.SYSCTL_CONF, "w") |
1868 | handle = mock_file() |
1869 | - handle.write.has_calls([ |
1870 | - mock.call('net.ipv4.ip_forward=1\n'), |
1871 | - mock.call('vm.swappiness=60\n'), |
1872 | - ]) |
1873 | - check_call.assert_called_with([ |
1874 | - 'sysctl', '-p', lib_sysconfig.SYSCTL_CONF |
1875 | - ]) |
1876 | + handle.write.has_calls( |
1877 | + [mock.call("net.ipv4.ip_forward=1\n"), mock.call("vm.swappiness=60\n")] |
1878 | + ) |
1879 | + check_call.assert_called_with(["sysctl", "-p", lib_sysconfig.SYSCTL_CONF]) |
1880 | |
1881 | @mock.patch("lib_sysconfig.hookenv") |
1882 | def test_update_sysctl_invalid_yaml(self, hookenv): |
1883 | @@ -676,8 +699,7 @@ class TestLib: |
1884 | with pytest.raises(Exception): |
1885 | sysh.update_sysctl() |
1886 | hookenv.log.assert_called_once_with( |
1887 | - "Error parsing sysctl YAML: {invalid", |
1888 | - level=hookenv.ERROR |
1889 | + "Error parsing sysctl YAML: {invalid", level=hookenv.ERROR |
1890 | ) |
1891 | hookenv.status_set.assert_called_once_with( |
1892 | "blocked", "Error parsing sysctl YAML" |
1893 | diff --git a/src/tox.ini b/src/tox.ini |
1894 | index 1b641ce..f932ee3 100644 |
1895 | --- a/src/tox.ini |
1896 | +++ b/src/tox.ini |
1897 | @@ -33,8 +33,11 @@ deps = -r{toxinidir}/tests/functional/requirements.txt |
1898 | -r{toxinidir}/requirements.txt |
1899 | |
1900 | [testenv:lint] |
1901 | -commands = flake8 |
1902 | +commands = |
1903 | + black --check reactive lib tests |
1904 | + flake8 |
1905 | deps = |
1906 | + black |
1907 | flake8 |
1908 | flake8-docstrings |
1909 | flake8-import-order |
1910 | @@ -47,5 +50,5 @@ exclude = |
1911 | .git, |
1912 | __pycache__, |
1913 | .tox, |
1914 | -max-line-length = 120 |
1915 | +max-line-length = 88 |
1916 | max-complexity = 10 |
This merge proposal is being monitored by mergebot. Change the status to Approved to merge.