Merge ~xavpaice/charm-sysconfig:linting into charm-sysconfig: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)
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

To post a comment you must log in.
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

This merge proposal is being monitored by mergebot. Change the status to Approved to merge.

Revision history for this message
Alvaro Uria (aluria) wrote :

+1

review: Approve
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

Change successfully merged at revision 1b3e8bb26e059993187aaf1485a761ecbbd95bba

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/lib/lib_sysconfig.py b/src/lib/lib_sysconfig.py
2index 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")
521diff --git a/src/reactive/sysconfig.py b/src/reactive/sysconfig.py
522index 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")
733diff --git a/src/tests/functional/conftest.py b/src/tests/functional/conftest.py
734index 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)
792diff --git a/src/tests/functional/juju_tools.py b/src/tests/functional/juju_tools.py
793index 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"]
854diff --git a/src/tests/functional/test_deploy.py b/src/tests/functional/test_deploy.py
855index 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
1397diff --git a/src/tests/unit/conftest.py b/src/tests/unit/conftest.py
1398index 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
1471diff --git a/src/tests/unit/test_lib.py b/src/tests/unit/test_lib.py
1472index 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"
1893diff --git a/src/tox.ini b/src/tox.ini
1894index 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

Subscribers

People subscribed via source and target branches

to all changes: