Merge ~xavpaice/charm-telegraf:lp1903499 into charm-telegraf:master

Proposed by Xav Paice
Status: Merged
Approved by: Drew Freiberger
Approved revision: d872ecb06e706b3be9ff9b0f700e39c75acb67b7
Merged at revision: 332c9c52a8b474b110c163684ab6e5bd5d29eb4e
Proposed branch: ~xavpaice/charm-telegraf:lp1903499
Merge into: charm-telegraf:master
Diff against target: 678 lines (+487/-97)
8 files modified
src/files/telegraf_exec_metrics.py (+30/-1)
src/tests/functional/tests/base.py (+76/-0)
src/tests/functional/tests/bundles/bionic-compute.yaml (+70/-0)
src/tests/functional/tests/bundles/focal-compute.yaml (+177/-0)
src/tests/functional/tests/test_compute.py (+49/-0)
src/tests/functional/tests/test_telegraf.py (+13/-79)
src/tests/functional/tests/tests.yaml (+23/-12)
src/tests/unit/test_telegraf.py (+49/-5)
Reviewer Review Type Date Requested Status
Drew Freiberger Approve
Canonical IS Reviewers Pending
Canonical IS Reviewers Pending
Benjamin Allot Pending
Xav Paice Pending
Peter Sabaini Pending
Review via email: mp+397116@code.launchpad.net

This proposal supersedes a proposal from 2021-01-27.

Commit message

OvsDumpFlowsCmdMetric: Use openflow protocol version to dump the flows

To post a comment you must log in.
Canonical IS Mergebot (canonical-is-mergebot) wrote : Posted in a previous version of this proposal

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

Benjamin Allot (ballot) wrote : Posted in a previous version of this proposal

LGTM.

Ran the tests locally with success and looked at the commands and their output on a compute node.

Not top approving as it requires bootstack reviews.

review: Approve
Peter Sabaini (peter-sabaini) wrote : Posted in a previous version of this proposal

Hey, thanks for the contribution.

I have only one minor nit inline.

Would it be possible to get some functional test coverage for this too?

Thank you,
peter.

review: Needs Fixing
Canonical IS Mergebot (canonical-is-mergebot) wrote : Posted in a previous version of this proposal

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

Drew Freiberger (afreiberger) wrote : Posted in a previous version of this proposal

All non-focal tests pass. there's issues with the upstream dependencies for focal-ussuri-ovn when running on lxd, I believe. (neutron-gateway hung on ovs add-bridge)

Suggest moving focal-compute to the smoke bundles and merging as is.

review: Approve
Hemanth Nakkina (hemanth-n) wrote : Posted in a previous version of this proposal

Hi Peter

Few questions:
1. Is the flows for ovs bridges for focal-compute created using OpenFlow13 protocol?

2. Can we add testcase to check for any plugin errors in telegraf logs.

+ def test_04_plugin_errors(self):
+ cmd = "cat /var/log/telegraf/telegraf.log"
+ content = model.run_on_unit(self.lead_unit_name, cmd)
+ logs = content.get('Stdout', None)
+ error_pattern = "E!"
+ self.assertFalse(re.findall(error_pattern, logs, flags=re.M))

3. I am able to get a focal-ovn bundle working with the following changes. Feel free to use them if you see appropriate and needed.
   Ran the bundle with command "tox -e func -- --keep-model -b ovn:focal-ovn"

   This deployment only creates br-int with openflow protocol default. By using configuration function zaza.openstack.charm_tests.neutron.setup.basic_overcloud_network, it creates br-ex with OpenFlow13. So this covers verifying the problem mentioned in this LP bug. ( We can ignore this if it is covered by my query 1)

   Patch with the changes tested (Ignore changes in tox.ini):
   https://pastebin.canonical.com/p/czwpCRypFF/

Xav Paice (xavpaice) wrote : Posted in a previous version of this proposal

I'm getting functest fails on xenial:

2021-01-28 16:09:12 [INFO] ======================================================================
2021-01-28 16:09:12 [INFO] FAIL: test_01_metrics_available (tests.test_telegraf.TestTelegraf)
2021-01-28 16:09:12 [INFO] ----------------------------------------------------------------------
2021-01-28 16:09:12 [INFO] Traceback (most recent call last):
2021-01-28 16:09:12 [INFO] File "./tests/test_telegraf.py", line 37, in test_01_metrics_available
2021-01-28 16:09:12 [INFO] self.check_metrics(re_patterns)
2021-01-28 16:09:12 [INFO] File "./tests/base.py", line 69, in check_metrics
2021-01-28 16:09:12 [INFO] self.check_re_pattern(re_pattern, text)
2021-01-28 16:09:12 [INFO] File "./tests/base.py", line 35, in check_re_pattern
2021-01-28 16:09:12 [INFO] self.assertTrue(re.findall(re_pattern, text, flags=re.M))
2021-01-28 16:09:12 [INFO] AssertionError: [] is not true

Xav Paice (xavpaice) wrote : Posted in a previous version of this proposal

bit more detail - I added a patch to get more detail:

diff --git a/src/tests/functional/tests/base.py b/src/tests/functional/tests/base.py
index 1197396..3433c5d 100644
--- a/src/tests/functional/tests/base.py
+++ b/src/tests/functional/tests/base.py
@@ -32,7 +32,8 @@ class BaseTelegrafTest(unittest.TestCase):
     def check_re_pattern(self, re_pattern, text):
         logging.info("checking metrics %s", re_pattern)
         # findall returns a list, [] when no match
- self.assertTrue(re.findall(re_pattern, text, flags=re.M))
+ self.assertTrue(re.findall(re_pattern, text, flags=re.M),
+ msg="Failed to find {}".format(re_pattern))

     def check_metrics(self, patterns):
         principal_units = (

2021-01-28 17:01:25 [INFO] ======================================================================
2021-01-28 17:01:25 [INFO] FAIL: test_01_metrics_available (tests.test_telegraf.TestTelegraf)
2021-01-28 17:01:25 [INFO] ----------------------------------------------------------------------
2021-01-28 17:01:25 [INFO] Traceback (most recent call last):
2021-01-28 17:01:25 [INFO] File "./tests/test_telegraf.py", line 37, in test_01_metrics_available
2021-01-28 17:01:25 [INFO] self.check_metrics(re_patterns)
2021-01-28 17:01:25 [INFO] File "./tests/base.py", line 70, in check_metrics
2021-01-28 17:01:25 [INFO] self.check_re_pattern(re_pattern, text)
2021-01-28 17:01:25 [INFO] File "./tests/base.py", line 35, in check_re_pattern
2021-01-28 17:01:25 [INFO] self.assertTrue(re.findall(re_pattern, text, flags=re.M),
2021-01-28 17:01:25 [INFO] AssertionError: [] is not true : Failed to find ^zoneinfo_
2021-01-28 17:01:25 [INFO] ----------------------------------------------------------------------

review: Needs Fixing
Peter Sabaini (peter-sabaini) wrote : Posted in a previous version of this proposal

Hey Xav,

both xenial-mysql and xenial-postgres succeed for me on branch lp1903499

https://pastebin.canonical.com/p/7ynsJnB9tt/

Can you repro the faults? Are other metrics missing as well on X?

cheers,
peter

Drew Freiberger (afreiberger) wrote : Posted in a previous version of this proposal

Hemanth:

Regarding focal-ovn, I think you're onto something. It indeed was hanging with this command (which is not using OpenFlow13):

ovs-vsctl -- --may-exist add-br br-int -- set bridge br-int external-ids:charm-neutron-gateway=manage

Care to provide a branch with that patch added, or integrate your fix into the already present focal-compute test?

At this point, while I think this is a worthy bug to close, we're very close to release cutoff, but the failure in testing is with neutron-openvswitch configuration, not telegraf itself.

Drew Freiberger (afreiberger) wrote : Posted in a previous version of this proposal

@xavpaice

here's my results on charmlab2 for xenial:

https://pastebin.canonical.com/p/ZrKbQmcYY2/

Peter Sabaini (peter-sabaini) wrote : Posted in a previous version of this proposal

Hemanth,

thanks for the patches. I have added the check for logs.

I see these protos avail in my test:

root@juju-322ca5-8:~# ovs-vsctl -f json find bridge name=br-data| json_pp | grep OpenFlow
               "OpenFlow10",
               "OpenFlow13",
               "OpenFlow14"

cheers,
peter.

Xav Paice (xavpaice) wrote : Posted in a previous version of this proposal

Raised LP: #1913645 for the test fail. It's not introduced by this change, and so is not a blocker.

Just running some extra tests now, from that last commit.

Xav Paice (xavpaice) wrote : Posted in a previous version of this proposal

2021-01-28 21:36:37 [INFO] ======================================================================
2021-01-28 21:36:37 [INFO] ERROR: test_04_plugin_errors (tests.test_compute.TestTelegrafCompute)
2021-01-28 21:36:37 [INFO] Check there are no plugin errors in the telegraf log file.
2021-01-28 21:36:37 [INFO] ----------------------------------------------------------------------
2021-01-28 21:36:37 [INFO] Traceback (most recent call last):
2021-01-28 21:36:37 [INFO] File "./tests/test_compute.py", line 41, in test_04_plugin_errors
2021-01-28 21:36:37 [INFO] self.lead_unit_name, "/var/log/telegraf/telegraf.log"
2021-01-28 21:36:37 [INFO] File "/home/xav/tmp/charm-telegraf/src/.tox/func/lib/python3.6/site-packages/zaza/model.py", line 1400, in file_contents
2021-01-28 21:36:37 [INFO] app, unit_id = unit_name.split("/")
2021-01-28 21:36:37 [INFO] AttributeError: 'NoneType' object has no attribute 'split'
2021-01-28 21:36:37 [INFO] ----------------------------------------------------------------------

The last commit introduces new test failures

review: Needs Fixing

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

Drew Freiberger (afreiberger) wrote :

LGTM, thanks for poking through those issues, Xav!

review: Approve
Drew Freiberger (afreiberger) wrote :

Still +1

review: Approve

Change successfully merged at revision 332c9c52a8b474b110c163684ab6e5bd5d29eb4e

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/files/telegraf_exec_metrics.py b/src/files/telegraf_exec_metrics.py
2index 7f9bfc3..fe31c81 100755
3--- a/src/files/telegraf_exec_metrics.py
4+++ b/src/files/telegraf_exec_metrics.py
5@@ -360,8 +360,37 @@ class OvsDumpFlowsCmdMetric(CmdMetric):
6
7 # query OVS for the list of bridges
8 bridges = self.get_cmd_output(["sudo", ovs_vsctl, "list-br"]).split()
9+
10 for bridge in bridges:
11- cmd = ["sudo", ovs_ofctl, "dump-flows", bridge]
12+ # find openflow protocol supported
13+ bridge_details_cmd = [
14+ "sudo",
15+ ovs_vsctl,
16+ "-f",
17+ "json",
18+ "find",
19+ "bridge",
20+ "name=" + bridge,
21+ ]
22+ bridge_details = self.get_cmd_output(bridge_details_cmd, is_json=True)
23+ protocol_index = bridge_details["headings"].index("protocols")
24+ # Ex: br_int_details['data'][0][protocol_index] is in format
25+ # ['set', ['OpenFlow13', 'OpenFlow15']]]
26+ supported_protocols = bridge_details["data"][0][protocol_index][1]
27+
28+ if supported_protocols:
29+ # pick the latest openflow protocol version
30+ cmd = [
31+ "sudo",
32+ ovs_ofctl,
33+ "dump-flows",
34+ "-O",
35+ supported_protocols[-1],
36+ bridge,
37+ ]
38+ else:
39+ cmd = ["sudo", ovs_ofctl, "dump-flows", bridge]
40+
41 output = self.get_cmd_output(cmd)
42 flows[bridge] = output
43
44diff --git a/src/tests/functional/tests/base.py b/src/tests/functional/tests/base.py
45new file mode 100644
46index 0000000..3433c5d
47--- /dev/null
48+++ b/src/tests/functional/tests/base.py
49@@ -0,0 +1,76 @@
50+import itertools as it
51+import logging
52+import re
53+import time
54+import unittest
55+
56+import requests
57+
58+from zaza import model
59+from zaza.utilities import juju
60+
61+
62+DEFAULT_HTTPGET_TIMEOUT = 10
63+DEFAULT_RETRIES = 12
64+DEFAULT_RETRIES_TIMEOUT = 5
65+DEFAULT_TELEGRAF_EXPORTER_PORT = "9103"
66+
67+
68+class BaseTelegrafTest(unittest.TestCase):
69+ """Base for Telegraf charm tests."""
70+
71+ @classmethod
72+ def setUpClass(cls):
73+ super(BaseTelegrafTest, cls).setUpClass()
74+ cls.model_name = model.get_juju_model()
75+ cls.application_name = "telegraf"
76+ cls.lead_unit_name = model.get_lead_unit_name(
77+ cls.application_name, model_name=cls.model_name
78+ )
79+ logging.debug("Leader unit is {}".format(cls.lead_unit_name))
80+
81+ def check_re_pattern(self, re_pattern, text):
82+ logging.info("checking metrics %s", re_pattern)
83+ # findall returns a list, [] when no match
84+ self.assertTrue(re.findall(re_pattern, text, flags=re.M),
85+ msg="Failed to find {}".format(re_pattern))
86+
87+ def check_metrics(self, patterns):
88+ principal_units = (
89+ model.get_units(app)
90+ for app in juju.get_principle_applications(self.application_name)
91+ )
92+
93+ for unit in it.chain.from_iterable(principal_units):
94+ if not unit.public_address:
95+ continue
96+ url = "http://{}:{}/metrics".format(
97+ unit.public_address, DEFAULT_TELEGRAF_EXPORTER_PORT
98+ )
99+
100+ for retry in range(DEFAULT_RETRIES):
101+ resp = requests.get(url, timeout=DEFAULT_HTTPGET_TIMEOUT)
102+ self.assertEqual(resp.status_code, 200)
103+
104+ if (
105+ unit.name.startswith("postgresql/")
106+ and "postgresql_blks_hit" not in resp.text # noqa W503
107+ ) or "cpu_usage_idle" not in resp.text:
108+ time.sleep(DEFAULT_RETRIES_TIMEOUT)
109+
110+ continue
111+
112+ logging.info("test_service: Unit {} is reachable".format(unit.name))
113+
114+ resp = requests.get(url)
115+ self.assertTrue(resp.ok)
116+ text = resp.text
117+
118+ for re_pattern in patterns:
119+ self.check_re_pattern(re_pattern, text)
120+
121+ break
122+ else:
123+ msg = "test_service: Unit {} is NOT reachable".format(unit.name)
124+ logging.error(msg)
125+ self.fail(msg)
126diff --git a/src/tests/functional/tests/bundles/bionic-compute.yaml b/src/tests/functional/tests/bundles/bionic-compute.yaml
127new file mode 100644
128index 0000000..bd1a67d
129--- /dev/null
130+++ b/src/tests/functional/tests/bundles/bionic-compute.yaml
131@@ -0,0 +1,70 @@
132+series: bionic
133+relations:
134+- - nova-compute:amqp
135+ - rabbitmq-server:amqp
136+- - nova-cloud-controller:shared-db
137+ - percona-cluster:shared-db
138+- - nova-cloud-controller:identity-service
139+ - keystone:identity-service
140+- - nova-cloud-controller:amqp
141+ - rabbitmq-server:amqp
142+- - nova-cloud-controller:cloud-compute
143+ - nova-compute:cloud-compute
144+- - keystone:shared-db
145+ - percona-cluster:shared-db
146+- - neutron-gateway:amqp
147+ - rabbitmq-server:amqp
148+- - nova-cloud-controller:quantum-network-service
149+ - neutron-gateway:quantum-network-service
150+- - neutron-api:shared-db
151+ - percona-cluster:shared-db
152+- - neutron-api:amqp
153+ - rabbitmq-server:amqp
154+- - neutron-api:neutron-api
155+ - nova-cloud-controller:neutron-api
156+- - neutron-api:identity-service
157+ - keystone:identity-service
158+- - nova-compute:neutron-plugin
159+ - neutron-openvswitch:neutron-plugin
160+- - rabbitmq-server:amqp
161+ - neutron-openvswitch:amqp
162+- - nova-compute:juju-info
163+ - telegraf:juju-info
164+applications:
165+ rabbitmq-server:
166+ charm: cs:~openstack-charmers-next/rabbitmq-server
167+ num_units: 1
168+ percona-cluster:
169+ charm: cs:~openstack-charmers-next/percona-cluster
170+ num_units: 1
171+ options:
172+ max-connections: 1000
173+ innodb-buffer-pool-size: 256M
174+ nova-cloud-controller:
175+ charm: cs:~openstack-charmers-next/nova-cloud-controller
176+ num_units: 1
177+ options:
178+ network-manager: Neutron
179+ debug: true
180+ neutron-api:
181+ charm: cs:~openstack-charmers-next/neutron-api
182+ num_units: 1
183+ options:
184+ flat-network-providers: physnet1
185+ neutron-security-groups: true
186+ keystone:
187+ charm: cs:~openstack-charmers-next/keystone
188+ num_units: 1
189+ neutron-gateway:
190+ charm: cs:~openstack-charmers-next/neutron-gateway
191+ num_units: 1
192+ options:
193+ bridge-mappings: physnet1:br-ex
194+ neutron-openvswitch:
195+ charm: cs:~openstack-charmers-next/neutron-openvswitch
196+ nova-compute:
197+ charm: cs:~openstack-charmers-next/nova-compute
198+ num_units: 1
199+ options:
200+ enable-live-migration: false
201+
202diff --git a/src/tests/functional/tests/bundles/focal-compute.yaml b/src/tests/functional/tests/bundles/focal-compute.yaml
203new file mode 100644
204index 0000000..ee56226
205--- /dev/null
206+++ b/src/tests/functional/tests/bundles/focal-compute.yaml
207@@ -0,0 +1,177 @@
208+variables:
209+ openstack-origin: &openstack-origin distro
210+
211+series: focal
212+
213+comment:
214+- 'machines section to decide order of deployment. database sooner = faster'
215+machines:
216+ '0':
217+ constraints: mem=3072M
218+ '1':
219+ constraints: mem=3072M
220+ '2':
221+ constraints: mem=3072M
222+ '3':
223+ '4':
224+ '5':
225+ '6':
226+ '7':
227+ '8':
228+ '9':
229+
230+
231+applications:
232+
233+ telegraf:
234+ num_units: 0
235+
236+ nova-cloud-controller-mysql-router:
237+ charm: cs:~openstack-charmers-next/mysql-router
238+ keystone-mysql-router:
239+ charm: cs:~openstack-charmers-next/mysql-router
240+ glance-mysql-router:
241+ charm: cs:~openstack-charmers-next/mysql-router
242+ neutron-api-mysql-router:
243+ charm: cs:~openstack-charmers-next/mysql-router
244+ placement-mysql-router:
245+ charm: cs:~openstack-charmers-next/mysql-router
246+
247+ mysql-innodb-cluster:
248+ charm: cs:~openstack-charmers-next/mysql-innodb-cluster
249+ num_units: 3
250+ options:
251+ source: *openstack-origin
252+ to:
253+ - '0'
254+ - '1'
255+ - '2'
256+
257+ rabbitmq-server:
258+ charm: cs:~openstack-charmers-next/rabbitmq-server
259+ num_units: 1
260+ options:
261+ source: *openstack-origin
262+ to:
263+ - '3'
264+
265+ nova-cloud-controller:
266+ charm: cs:~openstack-charmers-next/nova-cloud-controller
267+ num_units: 1
268+ options:
269+ openstack-origin: *openstack-origin
270+ network-manager: Neutron
271+ debug: true
272+ to:
273+ - '4'
274+
275+ neutron-api:
276+ charm: cs:~openstack-charmers-next/neutron-api
277+ num_units: 1
278+ options:
279+ manage-neutron-plugin-legacy-mode: true
280+ openstack-origin: *openstack-origin
281+ flat-network-providers: physnet1
282+ neutron-security-groups: true
283+ to:
284+ - '5'
285+
286+ keystone:
287+ charm: cs:~openstack-charmers-next/keystone
288+ num_units: 1
289+ options:
290+ openstack-origin: *openstack-origin
291+ to:
292+ - '6'
293+
294+ neutron-gateway:
295+ charm: cs:~openstack-charmers-next/neutron-gateway
296+ num_units: 1
297+ options:
298+ openstack-origin: *openstack-origin
299+ bridge-mappings: physnet1:br-ex
300+ to:
301+ - '7'
302+
303+ neutron-openvswitch:
304+ charm: cs:~openstack-charmers-next/neutron-openvswitch
305+
306+ placement:
307+ charm: cs:~openstack-charmers-next/placement
308+ num_units: 1
309+ options:
310+ openstack-origin: *openstack-origin
311+ to:
312+ - '9'
313+
314+ nova-compute:
315+ charm: cs:~openstack-charmers-next/nova-compute
316+ num_units: 1
317+ options:
318+ openstack-origin: *openstack-origin
319+ enable-live-migration: false
320+ to:
321+ - '8'
322+
323+relations:
324+ - - 'nova-compute:juju-info'
325+ - 'telegraf:juju-info'
326+
327+ - - 'nova-compute:amqp'
328+ - 'rabbitmq-server:amqp'
329+
330+ - - 'nova-cloud-controller:shared-db'
331+ - 'nova-cloud-controller-mysql-router:shared-db'
332+ - - 'nova-cloud-controller-mysql-router:db-router'
333+ - 'mysql-innodb-cluster:db-router'
334+
335+ - - 'nova-cloud-controller:identity-service'
336+ - 'keystone:identity-service'
337+
338+ - - 'nova-cloud-controller:amqp'
339+ - 'rabbitmq-server:amqp'
340+
341+ - - 'nova-cloud-controller:cloud-compute'
342+ - 'nova-compute:cloud-compute'
343+
344+ - - 'keystone:shared-db'
345+ - 'keystone-mysql-router:shared-db'
346+ - - 'keystone-mysql-router:db-router'
347+ - 'mysql-innodb-cluster:db-router'
348+
349+ - - 'neutron-gateway:amqp'
350+ - 'rabbitmq-server:amqp'
351+
352+ - - 'nova-cloud-controller:quantum-network-service'
353+ - 'neutron-gateway:quantum-network-service'
354+
355+ - - 'neutron-api:shared-db'
356+ - 'neutron-api-mysql-router:shared-db'
357+ - - 'neutron-api-mysql-router:db-router'
358+ - 'mysql-innodb-cluster:db-router'
359+
360+ - - 'neutron-api:amqp'
361+ - 'rabbitmq-server:amqp'
362+
363+ - - 'neutron-api:neutron-api'
364+ - 'nova-cloud-controller:neutron-api'
365+
366+ - - 'neutron-api:identity-service'
367+ - 'keystone:identity-service'
368+
369+ - - 'nova-compute:neutron-plugin'
370+ - 'neutron-openvswitch:neutron-plugin'
371+
372+ - - 'rabbitmq-server:amqp'
373+ - 'neutron-openvswitch:amqp'
374+
375+ - - 'placement:shared-db'
376+ - 'placement-mysql-router:shared-db'
377+ - - 'placement-mysql-router:db-router'
378+ - 'mysql-innodb-cluster:db-router'
379+
380+ - - 'placement:identity-service'
381+ - 'keystone:identity-service'
382+
383+ - - 'placement:placement'
384+ - 'nova-cloud-controller:placement'
385diff --git a/src/tests/functional/tests/test_compute.py b/src/tests/functional/tests/test_compute.py
386new file mode 100644
387index 0000000..db4f3b9
388--- /dev/null
389+++ b/src/tests/functional/tests/test_compute.py
390@@ -0,0 +1,49 @@
391+# Copyright 2015-2020 Canonical Ltd.
392+#
393+# This file is part of the Telegraf Charm for Juju.
394+#
395+# This program is free software: you can redistribute it and/or modify
396+# it under the terms of the GNU General Public License version 3, as
397+# published by the Free Software Foundation.
398+#
399+# This program is distributed in the hope that it will be useful, but
400+# WITHOUT ANY WARRANTY; without even the implied warranties of
401+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
402+# PURPOSE. See the GNU General Public License for more details.
403+#
404+# You should have received a copy of the GNU General Public License
405+# along with this program. If not, see <http://www.gnu.org/licenses/>.
406+import re
407+
408+from zaza import model
409+
410+from .base import BaseTelegrafTest
411+
412+
413+class TestTelegrafCompute(BaseTelegrafTest):
414+ def test_01_metrics_available(self):
415+ # check metrics are available
416+ re_patterns = [
417+ r"^sockstat_",
418+ r"^sockstat6_",
419+ r"^softnet_stat",
420+ r"^buddyinfo_",
421+ r"^zoneinfo_",
422+ r"^processes_",
423+ r"^ovs_dump_flows_count.*br-data",
424+ r"^ovs_dpctl_TX_errors.*br-data",
425+ ]
426+ self.check_metrics(re_patterns)
427+
428+ def test_04_plugin_errors(self):
429+ """Check there are no plugin errors in the telegraf log file."""
430+ content = model.file_contents(
431+ self.lead_unit_name, "/var/log/telegraf/telegraf.log"
432+ )
433+ # Sometimes, the logs show errors on Telegraf first start because br-int isn't
434+ # yet started. To overcome this, just check the most recent start of Telegraf.
435+ up_to_word = "I! Starting Telegraf"
436+ rx_to_last = r'^.*{}'.format(re.escape(up_to_word))
437+ last_logs = re.sub(rx_to_last, "", content, flags=re.DOTALL).strip()
438+ error_pattern = "E!"
439+ self.assertFalse(re.findall(error_pattern, last_logs, flags=re.M))
440diff --git a/src/tests/functional/tests/test_telegraf.py b/src/tests/functional/tests/test_telegraf.py
441index 3c4354d..33d29f1 100644
442--- a/src/tests/functional/tests/test_telegraf.py
443+++ b/src/tests/functional/tests/test_telegraf.py
444@@ -13,94 +13,28 @@
445 #
446 # You should have received a copy of the GNU General Public License
447 # along with this program. If not, see <http://www.gnu.org/licenses/>.
448-import itertools as it
449 import logging
450-import re
451-import time
452-import unittest
453-
454-import requests
455
456 from zaza import model
457-from zaza.utilities import juju
458
459-DEFAULT_HTTPGET_TIMEOUT = 10
460-DEFAULT_RETRIES = 12
461-DEFAULT_RETRIES_TIMEOUT = 5
462-DEFAULT_TELEGRAF_EXPORTER_PORT = "9103"
463+from .base import BaseTelegrafTest
464+
465 DEB_TELEGRAF_CONF = "/etc/telegraf/telegraf.conf"
466 SNAP_TELEGRAF_CONF = "/var/snap/telegraf/current/telegraf.conf"
467
468
469-class BaseTelegrafTest(unittest.TestCase):
470- """Base for Telegraf charm tests."""
471-
472- @classmethod
473- def setUpClass(cls):
474- super(BaseTelegrafTest, cls).setUpClass()
475- cls.model_name = model.get_juju_model()
476- cls.application_name = "telegraf"
477- cls.lead_unit_name = model.get_lead_unit_name(
478- cls.application_name, model_name=cls.model_name
479- )
480- logging.debug("Leader unit is {}".format(cls.lead_unit_name))
481-
482-
483 class TestTelegraf(BaseTelegrafTest):
484- def check_re_pattern(self, re_pattern, text):
485- logging.info("checking metrics %s", re_pattern)
486- # findall returns a list, [] when no match
487- self.assertTrue(re.findall(re_pattern, text, flags=re.M))
488-
489- def test_01_service(self):
490- principal_units = (
491- model.get_units(app)
492- for app in juju.get_principle_applications(self.application_name)
493- )
494-
495- for unit in it.chain.from_iterable(principal_units):
496- if not unit.public_address:
497- continue
498- url = "http://{}:{}/metrics".format(
499- unit.public_address, DEFAULT_TELEGRAF_EXPORTER_PORT
500- )
501-
502- for retry in range(DEFAULT_RETRIES):
503- resp = requests.get(url, timeout=DEFAULT_HTTPGET_TIMEOUT)
504- self.assertEqual(resp.status_code, 200)
505-
506- if (
507- unit.name.startswith("postgresql/")
508- and "postgresql_blks_hit" not in resp.text # noqa W503
509- ) or "cpu_usage_idle" not in resp.text:
510- time.sleep(DEFAULT_RETRIES_TIMEOUT)
511-
512- continue
513-
514- logging.info("test_service: Unit {} is reachable".format(unit.name))
515-
516- resp = requests.get(url)
517- self.assertTrue(resp.ok)
518- text = resp.text
519-
520- # check metrics are available
521- re_patterns = [
522- r"^sockstat_",
523- r"^sockstat6_",
524- r"^softnet_stat",
525- r"^buddyinfo_",
526- r"^zoneinfo_",
527- r"^processes_",
528- ]
529-
530- for re_pattern in re_patterns:
531- self.check_re_pattern(re_pattern, text)
532-
533- break
534- else:
535- msg = "test_service: Unit {} is NOT reachable".format(unit.name)
536- logging.error(msg)
537- self.fail(msg)
538+ def test_01_metrics_available(self):
539+ # check metrics are available
540+ re_patterns = [
541+ r"^sockstat_",
542+ r"^sockstat6_",
543+ r"^softnet_stat",
544+ r"^buddyinfo_",
545+ # r"^zoneinfo_", # commented because of LP1913645
546+ r"^processes_",
547+ ]
548+ self.check_metrics(re_patterns)
549
550 def test_02_telegraf_logfile(self):
551 """Check logfile parameter exists in ${BASE_DIR}/telegraf.conf."""
552diff --git a/src/tests/functional/tests/tests.yaml b/src/tests/functional/tests/tests.yaml
553index 2230082..7603b36 100644
554--- a/src/tests/functional/tests/tests.yaml
555+++ b/src/tests/functional/tests/tests.yaml
556@@ -1,18 +1,19 @@
557 charm_name: telegraf
558 gate_bundles:
559- - xenial-mysql
560- - xenial-postgres
561- - bionic-mysql
562- - bionic-postgres
563- - bionic-monitoring
564- - focal
565- - focal-snap
566+ - base: xenial-mysql
567+ - base: xenial-postgres
568+ - base: bionic-mysql
569+ - base: bionic-postgres
570+ - base: bionic-monitoring
571+ - base: focal
572+ - base: focal-snap
573+ - compute: focal-compute
574+ - compute: bionic-compute
575 smoke_bundles:
576- - bionic-postgres
577- - focal
578+ - base: bionic-postgres
579+ - base: focal
580 dev_bundles:
581- - bionic-postgres
582- - focal
583+ - compute: focal-compute
584 target_deploy_status:
585 telegraf:
586 workload-status-message: Monitoring
587@@ -20,5 +21,15 @@ target_deploy_status:
588 workload-status-message: Live
589 grafana:
590 workload-status-message: Started
591+ nova-cloud-controller:
592+ workload-status: blocked
593+ workload-status-message: "Missing relations: image"
594+ nova-compute:
595+ workload-status: blocked
596+ workload-status-message: "Missing relations: image"
597 tests:
598- - tests.test_telegraf.TestTelegraf
599+ - base:
600+ - tests.test_telegraf.TestTelegraf
601+ - compute:
602+ - tests.test_compute.TestTelegrafCompute
603+
604diff --git a/src/tests/unit/test_telegraf.py b/src/tests/unit/test_telegraf.py
605index 2cfbdc8..7179db6 100644
606--- a/src/tests/unit/test_telegraf.py
607+++ b/src/tests/unit/test_telegraf.py
608@@ -457,15 +457,56 @@ def test_ovs_dump_flows_cmd_metric(monkeypatch):
609 def mock_check_output(*args, **kwargs):
610 """Mock the subprocess calls to the OVS tools."""
611 cmd = args[0][1]
612- if cmd == "ovs-vsctl":
613- return b"br-ex\n"
614+ if cmd == "ovs-vsctl" and args[0][2] == "list-br":
615+ return b"br-ex\nbr-data\n"
616+ elif cmd == "ovs-vsctl" and args[0][6] == "name=br-ex":
617+ return (
618+ b'{"data":[[["uuid","8267c260-81d5-4a06-848f-711b82d9bf4b"],'
619+ b'["set",[]],["set",[]],"000062c26782064a","system","<unknown>",'
620+ b'["map",[]],["set",[]],["set",[]],["map",[]],["set",[]],false,'
621+ b'["set",[]],"br-ex",["set",[]],["map",[]],'
622+ b'["uuid","c1b763d1-a706-46af-98a8-4b4bd0125249"],["set",[]],false,'
623+ b'["map",[]],["set",[]],["map",[]],false]],'
624+ b'"headings":["_uuid","auto_attach","controller","datapath_id",'
625+ b'"datapath_type","datapath_version","external_ids","fail_mode",'
626+ b'"flood_vlans","flow_tables","ipfix","mcast_snooping_enable",'
627+ b'"mirrors","name","netflow","other_config","ports","protocols",'
628+ b'"rstp_enable","rstp_status","sflow","status","stp_enable"]}'
629+ )
630+ elif cmd == "ovs-vsctl" and args[0][6] == "name=br-data":
631+ return (
632+ b'{"data":[[["uuid","8267c260-81d5-4a06-848f-711b82d9bf4c"],'
633+ b'["set",[]],["set",[]],"000062c26782064b","system","<unknown>",'
634+ b'["map",[]],["set",[]],["set",[]],["map",[]],["set",[]],false,'
635+ b'["set",[]],"br-data",["set",[]],["map",[]],'
636+ b'["uuid","c1b763d1-a706-46af-98a8-4b4bd0125250"],'
637+ b'["set",["OpenFlow13", "OpenFlow15"]],false,["map",[]],'
638+ b'["set",[]],["map",[]],false]],'
639+ b'"headings":["_uuid","auto_attach","controller","datapath_id",'
640+ b'"datapath_type","datapath_version","external_ids","fail_mode",'
641+ b'"flood_vlans","flow_tables","ipfix","mcast_snooping_enable",'
642+ b'"mirrors","name","netflow","other_config","ports","protocols",'
643+ b'"rstp_enable","rstp_status","sflow","status","stp_enable"]}'
644+ )
645 elif (
646 cmd == "ovs-ofctl" and args[0][3] == "br-ex"
647 ): # sudo ovs-ofctl dump-flows br-ex
648 return (
649 b"NXST_FLOW reply (xid=0x4):\n"
650- b' cookie=0x3711311ec90146a9, duration=247966.151s, table=0, n_packets=0, n_bytes=0, priority=2,in_port="phy-br-ex" actions=drop\n' # noqa E501
651- b" cookie=0x3711311ec90146a9, duration=247966.175s, table=0, n_packets=2192, n_bytes=156148, priority=0 actions=NORMAL\n" # noqa E501
652+ b" cookie=0x3711311ec90146a9, duration=247966.1s, table=0, n_packets=0,"
653+ b'n_bytes=0, priority=2,in_port="phy-br-ex" actions=drop\n'
654+ b" cookie=0x3711311ec90146a9, duration=247966.5s, table=0, n_packets=2,"
655+ b"n_bytes=156148, priority=0 actions=NORMAL\n"
656+ )
657+ elif (
658+ cmd == "ovs-ofctl" and args[0][5] == "br-data"
659+ ): # sudo ovs-ofctl dump-flows br-data
660+ return (
661+ b"NXST_FLOW reply (xid=0x4):\n"
662+ b" cookie=0x3711311ec90146a0, duration=247966.1s, table=0, n_packets=0,"
663+ b'n_bytes=0, priority=2,in_port="phy-br-data" actions=drop\n'
664+ b" cookie=0x3711311ec90146a0, duration=247966.5s, table=0, n_packets=2,"
665+ b"n_bytes=156148, priority=0 actions=NORMAL\n"
666 )
667 else:
668 raise Exception("unexpected argument: {}".format(args))
669@@ -479,7 +520,10 @@ def test_ovs_dump_flows_cmd_metric(monkeypatch):
670
671 raw_output = metric.get_input_content()
672 parsed_output = metric.parse(raw_output)
673- expected_output = [{"bridge": "br-ex", "count": 2}]
674+ expected_output = [
675+ {"bridge": "br-ex", "count": 2},
676+ {"bridge": "br-data", "count": 2},
677+ ]
678 assert parsed_output == expected_output
679
680

Subscribers

People subscribed via source and target branches