Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests for mysql prometheus exporter #1155

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 125 additions & 0 deletions zaza/openstack/charm_tests/mysql/test_prometheus_mysql_exporter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Copyright 2022 Canonical Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""MySQL Prometheus Exporter Testing."""

import json
import urllib.request

import zaza.model as zaza_model
from zaza.openstack.charm_tests.mysql.tests import MySQLBaseTest


class PrometheusMySQLExporterTest(MySQLBaseTest):
"""Functional tests check prometheus exporter."""

@classmethod
def setUpClass(cls, application_name=None):
"""Run class setup for running mysql tests."""
super().setUpClass(application_name="mysql-innodb-cluster")
cls.application = "mysql-innodb-cluster"
cls.snap_name = "mysqld-exporter"
cls.service_name = "snap.mysqld-exporter.mysqld-exporter.service"

def _exporter_http_check(
self,
cmd,
expected,
):
"""Exec check cmd on each unit in the application.

:param cmd: The check command run on unit
:type cmd: str
:param expected: Expected result code
:type expected: str
"""
for unit in zaza_model.get_units(self.application):
result = zaza_model.run_on_unit(unit.name, cmd)
self.assertEqual(result.get("Code"), expected)

def _check_service_status_is(
self,
active=True,
):
cmd = "systemctl is-active {}".format(
self.service_name
)
excepted = "active\n"
if not active:
excepted = "inactive\n"
for unit in zaza_model.get_units(self.application):
result = zaza_model.run_on_unit(unit.name, cmd)
self.assertEqual(result.get("stdout"), excepted)

def test_01_exporter_http_check(self):
"""Check exporter endpoint is working."""
self._exporter_http_check(
cmd="curl http://localhost:9104",
expected="0",
)

for unit in zaza_model.get_units(self.application):
url = "http://{}:9104/metrics".format(
unit.public_address)
with urllib.request.urlopen(url) as resp:
metrics = resp.read().decode("utf-8")
if not any(
str(line) == "mysql_up 1"
for line in metrics.split("\n")
):
self.fail(
"Exporter permission not correct on {}".format(
unit.public_address
)
)

def test_02_exporter_service_relation_trigger(self):
"""Relation trigger exporter service start/stop."""
zaza_model.remove_relation(
self.application,
"prometheus2:target",
"mysql-innodb-cluster:prometheus",
)
for unit in zaza_model.get_units(self.application):
zaza_model.block_until_unit_wl_status(unit.name, "active")
zaza_model.block_until_all_units_idle()
self._check_service_status_is(active=False)

# Recover
zaza_model.add_relation(
self.application,
"prometheus2:target",
"mysql-innodb-cluster:prometheus",
)
for unit in zaza_model.get_units(self.application):
zaza_model.block_until_unit_wl_status(unit.name, "active")
zaza_model.block_until_all_units_idle()
self._check_service_status_is(active=True)

def test_03_snap_config(self):
"""Check snap set config is working."""
cmd = "sudo snap get {} mysql -d".format(self.snap_name)
for unit in zaza_model.get_units(self.application):
result = zaza_model.run_on_unit(unit.name, cmd)
json_mysql_config = json.loads(
result.get("stdout")).get("mysql")
json_mysql_config.pop("password")
self.assertEqual(
json_mysql_config,
{
"host": unit.public_address,
"port": 3306,
"user": "prom_exporter"
}
)
63 changes: 63 additions & 0 deletions zaza/openstack/charm_tests/mysql/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1127,3 +1127,66 @@ def test_910_restart_on_config_change(self):
{}, {},
self.services)
logging.info("Passed restart on changed test.")

def test_920_mysqlrouter_conf_broken(self):
"""Checking conf broken case.

Run the bootstrap when conf is broken
"""
# application_name on test is keystone-mysql-router
# using self.conf_file introduces error.
# instead of changing current self.conf_file,
# define one (it could introduce another issue)
config_file = (
"/var/lib/mysql/{}/mysqlrouter.conf"
.format(self.application_name))

logging.info("Starting broken conf test")

# put empty string to conf_file and make it wrong
logging.info("Breaking configuration file")
zaza.model.run_on_leader(self.application,
"echo '[DEFAULT]\n \
[metadata_cache:[\\w$]+$] \
' > {}".format(
config_file))

logging.info("Getting configuration file")
recovered = zaza.model.run_on_leader(self.application,
"cat {}".format(
config_file))['Stdout']

# Checking conf file length,
# if file is broken it is around 250
assert len(recovered) < 1000, (
"Breaking mysqlrouter conf failed.")

# verify it is in error state
for attempt in tenacity.Retrying(
reraise=True,
wait=tenacity.wait_fixed(10),
stop=tenacity.stop_after_attempt(30),
):
with attempt:
# update status to make the status error
logging.info("Run update-status")
self.run_update_status_hooks(['keystone-mysql-router/0'])

# get current status
unit_status = (zaza.model.get_status()
.applications
['keystone-mysql-router']['status'])
logging.info("Status:{}".format(unit_status['status']))
self.assertEqual(unit_status['status'], "active")

logging.info("Getting configuration file")
recovered = zaza.model.run_on_leader(self.application,
"cat {}".format(
config_file))['Stdout']

# Checking conf file length,
# if file is broken it is around 250
assert len(recovered) > 1000, (
"Fixing mysqlrouter conf failed.")

logging.info("Passed broken conf test.")
Loading