Merge ~barryprice/charm-canonical-livepatch/+git/canonical-livepatch-charm:zazatests into ~livepatch-charmers/charm-canonical-livepatch:master

Proposed by Barry Price
Status: Work in progress
Proposed branch: ~barryprice/charm-canonical-livepatch/+git/canonical-livepatch-charm:zazatests
Merge into: ~livepatch-charmers/charm-canonical-livepatch:master
Diff against target: 506 lines (+140/-215)
12 files modified
.gitignore (+1/-0)
Makefile (+11/-21)
dev/null (+0/-159)
files/check_canonical-livepatch.py (+1/-3)
metadata.yaml (+1/-1)
reactive/canonical_livepatch.py (+11/-29)
test-requirements.txt (+1/-0)
tests/basic_deployment.py (+13/-0)
tests/bundles/bionic.yaml (+18/-0)
tests/bundles/xenial.yaml (+18/-0)
tests/tests.yaml (+21/-2)
tox.ini (+44/-0)
Reviewer Review Type Date Requested Status
Livepatch charm developers Pending
Review via email: mp+369790@code.launchpad.net

Commit message

First pass at switching from amulet to tox+zaza for tests. Also dropping official support for Trusty as it's EOL. Oh, and some reformatting via `black`.

To post a comment you must log in.
3b5ee0d... by Barry Price

Obsolete comment removed

4bfc463... by Barry Price

Basic tests for an LXD deploy, need to figure out whether/how we can require an OpenStack controller for some test suites

Unmerged commits

4bfc463... by Barry Price

Basic tests for an LXD deploy, need to figure out whether/how we can require an OpenStack controller for some test suites

3b5ee0d... by Barry Price

Obsolete comment removed

f8061f8... by Barry Price

First pass at switching from amulet to tox+zaza for tests. Also dropping official support for Trusty as it's EOL

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/.gitignore b/.gitignore
0new file mode 1006440new file mode 100644
index 0000000..33defe4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
1.tox/
diff --git a/Makefile b/Makefile
index e7f78ad..7459cb2 100644
--- a/Makefile
+++ b/Makefile
@@ -5,35 +5,25 @@ all: test
55
6.PHONY: clean6.PHONY: clean
7clean:7clean:
8 @rm -f .unit-state.db
9 @find . -name "*.pyc" -type f -exec rm -f '{}' \;8 @find . -name "*.pyc" -type f -exec rm -f '{}' \;
10 @find . -name "__pycache__" -type d -prune -exec rm -rf '{}' \;9 @find . -name "__pycache__" -type d -prune -exec rm -rf '{}' \;
1110
12.PHONY: testdeps
13testdeps:
14 @sudo apt-get update
15 @sudo apt-get install -y make flake8 python3-flake8 python3-pip python-pip snapd libffi-dev
16 @which juju >/dev/null || (sudo snap install juju --classic)
17 @which charm >/dev/null || (sudo snap install charm --classic)
18 @which bundletester >/dev/null || (pip2 install bundletester juju-deployer)
19 @pip3 install amulet
20
21.PHONY: lint11.PHONY: lint
22lint:12lint:
23 @flake8 --max-complexity=16 --max-line-length=120 --exclude=lib/* && echo OK13 @echo "Normalising python layout with black."
14 @tox -e black
15 @echo "Running flake8"
16 @tox -e lint
2417
25.PHONY: charmbuild18.PHONY: charmbuild
26charmbuild:19charmbuild:
27 mkdir $(BUILDDEST)20 mkdir -p $(BUILDDEST)
28 charm build --output-dir $(BUILDDEST) --report21 charm build --output-dir $(BUILDDEST) --report
2922
30.PHONY: test23.PHONY: smoketest
31test: check-jujumodel24smoketest:
32 @echo "Running functional tests (including lint and unit tests)..."25 @tox -e func-smoke
33 bundletester -t $(BUILTCHARMDIR) -Fvl DEBUG -e $(JUJU_MODEL)
3426
35.PHONY: check-jujumodel27.PHONY: test
36check-jujumodel:28test:
37ifndef JUJU_MODEL29 @tox -e func
38 $(error JUJU_MODEL is undefined)
39endif
diff --git a/files/check_canonical-livepatch.py b/files/check_canonical-livepatch.py
index cafd472..0006714 100755
--- a/files/check_canonical-livepatch.py
+++ b/files/check_canonical-livepatch.py
@@ -142,9 +142,7 @@ def is_container():
142def main():142def main():
143 arch = os.uname()[4]143 arch = os.uname()[4]
144 if arch not in supported_archs:144 if arch not in supported_archs:
145 raise nagios_plugin3.CriticalError(145 raise nagios_plugin3.CriticalError("canonical-livepatch not supported on this architecture ({}).".format(arch))
146 "canonical-livepatch not supported on this architecture ({}).".format(arch)
147 )
148 elif is_container():146 elif is_container():
149 print("canonical-livepatch not needed in OS containers.")147 print("canonical-livepatch not needed in OS containers.")
150 else:148 else:
diff --git a/metadata.yaml b/metadata.yaml
index 6c22c45..e3e557f 100644
--- a/metadata.yaml
+++ b/metadata.yaml
@@ -2,7 +2,7 @@ name: canonical-livepatch
2display-name: Canonical Livepatch2display-name: Canonical Livepatch
3summary: Ubuntu Linux Livepatching Utility and Daemon3summary: Ubuntu Linux Livepatching Utility and Daemon
4maintainer: Livepatch charm developers <livepatch-charmers@lists.launchpad.net>4maintainer: Livepatch charm developers <livepatch-charmers@lists.launchpad.net>
5series: ['bionic', 'xenial', 'trusty']5series: ['bionic', 'xenial']
6description: |6description: |
7 This charms installs and configures the Ubuntu Linux Livepatching Utility and Daemon7 This charms installs and configures the Ubuntu Linux Livepatching Utility and Daemon
8tags:8tags:
diff --git a/reactive/canonical_livepatch.py b/reactive/canonical_livepatch.py
index f9c1e6e..30692a1 100644
--- a/reactive/canonical_livepatch.py
+++ b/reactive/canonical_livepatch.py
@@ -19,12 +19,7 @@ def file_to_units(local_path, unit_path):
19 perms = 0o64419 perms = 0o644
2020
21 fh = open(local_path, 'r')21 fh = open(local_path, 'r')
22 write_file(22 write_file(path=unit_path, content=fh.read().encode(), owner='root', perms=perms)
23 path=unit_path,
24 content=fh.read().encode(),
25 owner='root',
26 perms=perms,
27 )
2823
2924
30def wait_for_path(file_path, timeout=30):25def wait_for_path(file_path, timeout=30):
@@ -74,12 +69,7 @@ def write_status_to_disk():
7469
75 current_status = get_livepatch_status()70 current_status = get_livepatch_status()
76 perms = 0o64471 perms = 0o644
77 write_file(72 write_file(path='/var/lib/nagios/canonical-livepatch-status.txt', content=current_status, owner='root', perms=perms)
78 path='/var/lib/nagios/canonical-livepatch-status.txt',
79 content=current_status,
80 owner='root',
81 perms=perms,
82 )
8373
8474
85def get_patch_details():75def get_patch_details():
@@ -161,7 +151,7 @@ register_trigger(when='config.changed.livepatch_proxy', clear_flag='livepatch-pr
161@when_not('canonical-livepatch.supported')151@when_not('canonical-livepatch.supported')
162def livepatch_supported():152def livepatch_supported():
163 arch = uname()[4]153 arch = uname()[4]
164 supported_archs = ['x86_64', ]154 supported_archs = ['x86_64']
165 if arch not in supported_archs:155 if arch not in supported_archs:
166 hookenv.log('Livepatch does not currently support {} architecture'.format(arch))156 hookenv.log('Livepatch does not currently support {} architecture'.format(arch))
167 unit_update('blocked', 'Architecture {} is not supported by livepatch'.format(arch))157 unit_update('blocked', 'Architecture {} is not supported by livepatch'.format(arch))
@@ -177,7 +167,7 @@ def livepatch_supported():
177def install_livepatch():167def install_livepatch():
178 config = hookenv.config()168 config = hookenv.config()
179 snap_channel = config.get('snap_channel')169 snap_channel = config.get('snap_channel')
180 snap.install('canonical-livepatch', **{'channel': snap_channel, })170 snap.install('canonical-livepatch', **{'channel': snap_channel})
181171
182172
183@when('snap.installed.canonical-livepatch')173@when('snap.installed.canonical-livepatch')
@@ -210,8 +200,8 @@ def proxy_settings():
210@when('livepatch-proxy.configured')200@when('livepatch-proxy.configured')
211@when_not('canonical-livepatch.connected')201@when_not('canonical-livepatch.connected')
212def canonical_livepatch_connect():202def canonical_livepatch_connect():
213 # So if we've just installed snapd on a trusty system, we will not be on203 # So if we've just installed snapd on a trusty system, or are somehow
214 # the HWE kernel yet and unfortunately need to reboot first!204 # running an older kernel onto a supported series, we will need to reboot
215 current = LooseVersion(uname()[2])205 current = LooseVersion(uname()[2])
216 required = LooseVersion('4.4')206 required = LooseVersion('4.4')
217 uptrack_path = '/usr/sbin/uptrack-upgrade'207 uptrack_path = '/usr/sbin/uptrack-upgrade'
@@ -250,7 +240,7 @@ def change_channel():
250 config = hookenv.config()240 config = hookenv.config()
251 snap_channel = config.get('snap_channel')241 snap_channel = config.get('snap_channel')
252 # refresh to the given channel242 # refresh to the given channel
253 snap.refresh('canonical-livepatch', **{'channel': snap_channel, })243 snap.refresh('canonical-livepatch', **{'channel': snap_channel})
254244
255245
256# Set up Nagios checks when the nrpe-external-master subordinate is related246# Set up Nagios checks when the nrpe-external-master subordinate is related
@@ -266,28 +256,20 @@ def configure_nagios(nagios):
266 nrpe_setup = nrpe.NRPE(hostname=hostname, primary=False)256 nrpe_setup = nrpe.NRPE(hostname=hostname, primary=False)
267257
268 # install nagios support files258 # install nagios support files
269 file_to_units(259 file_to_units('files/check_canonical-livepatch.cron', '/etc/cron.d/check_canonical-livepatch')
270 'files/check_canonical-livepatch.cron',260 file_to_units('files/check_canonical-livepatch.py', '/usr/lib/nagios/plugins/check_canonical-livepatch.py')
271 '/etc/cron.d/check_canonical-livepatch',
272 )
273 file_to_units(
274 'files/check_canonical-livepatch.py',
275 '/usr/lib/nagios/plugins/check_canonical-livepatch.py',
276 )
277261
278 # write current status to disk to satisfy the nagios check262 # write current status to disk to satisfy the nagios check
279 write_status_to_disk()263 write_status_to_disk()
280264
281 # remove check from previous release with poorly formed name265 # remove check from previous release with poorly formed name
282 nrpe_setup.remove_check(266 nrpe_setup.remove_check(shortname='check_canonical-livepatch')
283 shortname='check_canonical-livepatch'
284 )
285267
286 # use charmhelpers to create the check268 # use charmhelpers to create the check
287 nrpe_setup.add_check(269 nrpe_setup.add_check(
288 'canonical-livepatch',270 'canonical-livepatch',
289 'Verify canonical-livepatch is working',271 'Verify canonical-livepatch is working',
290 '/usr/lib/nagios/plugins/check_canonical-livepatch.py'272 '/usr/lib/nagios/plugins/check_canonical-livepatch.py',
291 )273 )
292274
293 nrpe_setup.write()275 nrpe_setup.write()
diff --git a/test-requirements.txt b/test-requirements.txt
294new file mode 100644276new file mode 100644
index 0000000..b7c9112
--- /dev/null
+++ b/test-requirements.txt
@@ -0,0 +1 @@
1git+https://github.com/openstack-charmers/zaza.git#egg=zaza
diff --git a/tests/basic_deployment.py b/tests/basic_deployment.py
0new file mode 1006442new file mode 100644
index 0000000..a07e880
--- /dev/null
+++ b/tests/basic_deployment.py
@@ -0,0 +1,13 @@
1#!/usr/bin/python3
2
3import unittest
4
5import zaza.model as model
6
7
8class BasicDeployment(unittest.TestCase):
9 def test_ubuntu_series(self):
10 first_unit = model.get_units('mongo')[0]
11 result = model.run_on_leader('mongo', 'lsb_release -cs')
12 self.assertEqual(result['Code'], '0')
13 self.assertEqual(result['Stdout'].strip(), first_unit.series)
diff --git a/tests/bundles/bionic.yaml b/tests/bundles/bionic.yaml
0new file mode 10064414new file mode 100644
index 0000000..f95419d
--- /dev/null
+++ b/tests/bundles/bionic.yaml
@@ -0,0 +1,18 @@
1series: bionic
2applications:
3 mongo:
4 charm: cs:mongodb
5 num_units: 1
6 livepatch:
7 charm: ../../../builds/canonical-livepatch
8 series: bionic
9 nrpe:
10 charm: cs:nrpe
11 num_units: 0
12relations:
13 - - mongo
14 - livepatch
15 - - mongo
16 - nrpe:nrpe-external-master
17 - - livepatch
18 - nrpe:nrpe-external-master
diff --git a/tests/bundles/xenial.yaml b/tests/bundles/xenial.yaml
0new file mode 10064419new file mode 100644
index 0000000..5b52957
--- /dev/null
+++ b/tests/bundles/xenial.yaml
@@ -0,0 +1,18 @@
1series: xenial
2applications:
3 mongo:
4 charm: cs:mongodb
5 num_units: 1
6 livepatch:
7 charm: ../../../builds/canonical-livepatch
8 series: xenial
9 nrpe:
10 charm: cs:nrpe
11 num_units: 0
12relations:
13 - - mongo
14 - livepatch
15 - - mongo
16 - nrpe:nrpe-external-master
17 - - livepatch
18 - nrpe:nrpe-external-master
diff --git a/tests/multiseries b/tests/multiseries
0deleted file mode 10075519deleted file mode 100755
index 55adc62..0000000
--- a/tests/multiseries
+++ /dev/null
@@ -1,159 +0,0 @@
1#!/usr/bin/env python3
2
3import amulet
4import unittest
5from time import sleep
6from yaml import safe_load
7
8
9class TestDeployment(unittest.TestCase):
10 series = 'bionic' # latest LTS
11
12 @classmethod
13 def setUpClass(cls):
14 cls.deployment = amulet.Deployment(series=cls.series)
15
16 # deploy mongodb as our parent
17 cls.deployment.add('mongodb-{}'.format(cls.series), 'mongodb')
18
19 # deploy our own charm
20 cls.deployment.add('livepatch-{}'.format(cls.series), 'canonical-livepatch')
21
22 # and deploy the nrpe subordinate to test nagios checks
23 cls.deployment.add('nrpe-{}'.format(cls.series), 'nrpe')
24
25 # set nrpe to export its definitions
26 cls.deployment.configure('nrpe-{}'.format(cls.series), {
27 'export_nagios_definitions': True,
28 })
29
30 # relate subordinates to parent charm
31 cls.deployment.relate(
32 'mongodb-{}:juju-info'.format(cls.series),
33 'livepatch-{}:juju-info'.format(cls.series)
34 )
35 cls.deployment.relate(
36 'mongodb-{}:nrpe-external-master'.format(cls.series),
37 'nrpe-{}:nrpe-external-master'.format(cls.series)
38 )
39
40 # relate livepatch to nrpe for its own nagios checks
41 cls.deployment.relate(
42 'livepatch-{}:nrpe-external-master'.format(cls.series),
43 'nrpe-{}:nrpe-external-master'.format(cls.series)
44 )
45
46 try:
47 cls.deployment.setup(timeout=3600)
48 cls.deployment.sentry.wait()
49 except amulet.helpers.TimeoutError:
50 amulet.raise_status(
51 amulet.SKIP,
52 msg="Environment wasn't stood up in time"
53 )
54
55 def test_install(self):
56 livepatch = self.deployment.sentry['livepatch-{}'.format(self.series)][0]
57
58 # verify the snap was installed
59 output, exit_code = livepatch.run(
60 'stat /snap/bin/canonical-livepatch'
61 )
62 self.assertEqual(exit_code, 0)
63
64 def test_status(self):
65 livepatch = self.deployment.sentry['livepatch-{}'.format(self.series)][0]
66
67 # run a status check - we expect this to return 1 due to no access key
68 output, exit_code = livepatch.run('sudo canonical-livepatch status')
69 self.assertEqual(exit_code, 1)
70
71 def test_nagios_init(self):
72 livepatch = self.deployment.sentry['livepatch-{}'.format(self.series)][0]
73
74 # check for nagios bits
75 for path in [
76 '/etc/cron.d/check_canonical-livepatch',
77 '/usr/lib/nagios/plugins/check_canonical-livepatch.py',
78 '/var/lib/nagios/canonical-livepatch-status.txt'
79 ]:
80 output, exit_code = livepatch.run('stat {}'.format(path))
81 self.assertEqual(exit_code, 0)
82
83 def test_nagios_context_change(self):
84 livepatch = self.deployment.sentry['livepatch-{}'.format(self.series)][0]
85
86 test_context_name = 'amulet1'
87
88 # set context name
89 self.deployment.configure('livepatch-{}'.format(self.series), {
90 'nagios_context': test_context_name,
91 })
92
93 # nrpe updates can take a while
94 sleep(30)
95
96 # confirm it showed up in the right place
97 output, exit_code = livepatch.run(
98 'grep {} /var/lib/nagios/export/'
99 'service__*_check_canonical-livepatch'
100 '.cfg'.format(test_context_name))
101 self.assertEqual(exit_code, 0)
102
103 def test_channel_change(self):
104 livepatch = self.deployment.sentry['livepatch-{}'.format(self.series)][0]
105
106 # verify the current channel
107 output, exit_code = livepatch.run('snap info canonical-livepatch')
108 self.assertEqual(exit_code, 0)
109
110 # confirm we're tracking 'stable'
111 output_yaml = safe_load(output)
112 channel = output_yaml['tracking']
113 self.assertEqual(channel, 'stable')
114
115 # change channel to 'beta'
116 self.deployment.configure('livepatch-{}'.format(self.series), {
117 'snap_channel': 'beta',
118 })
119
120 # wait for that to settle
121 sleep(30)
122
123 # verify the current channel
124 output, exit_code = livepatch.run('snap info canonical-livepatch')
125 self.assertEqual(exit_code, 0)
126
127 # confirm we're tracking 'beta'
128 output_yaml = safe_load(output)
129 channel = output_yaml['tracking']
130 self.assertEqual(channel, 'beta')
131
132 def test_nagios_servicegroup_change(self):
133 livepatch = self.deployment.sentry['livepatch-{}'.format(self.series)][0]
134
135 test_servicegroup_name = 'amulet2'
136
137 # set servicegroup name
138 self.deployment.configure('livepatch-{}'.format(self.series), {
139 'nagios_servicegroups': test_servicegroup_name,
140 })
141
142 # nrpe updates can take a while
143 sleep(30)
144
145 # confirm it showed up in the right place
146 output, exit_code = livepatch.run(
147 'grep {} /var/lib/nagios/export/'
148 'service__*_check_canonical-livepatch'
149 '.cfg'.format(test_servicegroup_name)
150 )
151 self.assertEqual(exit_code, 0)
152
153
154class TestXenialDeployment(TestDeployment):
155 series = 'xenial'
156
157
158if __name__ == '__main__':
159 unittest.main()
diff --git a/tests/tests.yaml b/tests/tests.yaml
index 757bcc2..2754f7c 100644
--- a/tests/tests.yaml
+++ b/tests/tests.yaml
@@ -1,2 +1,21 @@
1makefile:1charm-name: canonical-livepatch
2 - lint2tests:
3 - zaza.charm_tests.noop.tests.NoopTest
4configure:
5 - zaza.charm_tests.noop.setup.basic_setup
6gate_bundles:
7 - bionic
8smoke_bundles:
9 - bionic
10tests:
11 - tests.basic_deployment.BasicDeployment
12target_deploy_status:
13 mongo:
14 workload-status: active
15 workload-status-message: Unit is ready
16 livepatch:
17 workload-status: blocked
18 workload-status-message: Livepatch is not needed in OS containers
19 nrpe:
20 workload-status: active
21 workload-status-message: ready
diff --git a/tox.ini b/tox.ini
3new file mode 10064422new file mode 100644
index 0000000..4b3e051
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,44 @@
1[tox]
2envlist = pep8
3skipsdist = True
4
5[testenv]
6setenv = VIRTUAL_ENV={envdir}
7 PYTHONHASHSEED=0
8whitelist_externals = juju
9passenv = HOME TERM CS_API_* OS_* AMULET_*
10deps = -r{toxinidir}/test-requirements.txt
11install_command =
12 pip install {opts} {packages}
13
14[testenv:proof]
15basepython = python3
16deps=charm-tools
17commands = charm-proof
18
19[testenv:black]
20commands = black --skip-string-normalization --line-length=120 .
21deps = black
22
23[testenv:lint]
24commands = flake8
25deps = flake8
26
27[testenv:func-noop]
28basepython = python3
29commands =
30 true
31
32[testenv:func]
33basepython = python3
34commands =
35 functest-run-suite --keep-model
36
37[testenv:func-smoke]
38basepython = python3
39commands =
40 functest-run-suite --keep-model --smoke
41
42[testenv:venv]
43commands = {posargs}
44

Subscribers

People subscribed via source and target branches