Merge ~ballot/charm-mongodb/+git/charm-mongodb:LP#1930552 into charm-mongodb:master

Proposed by Benjamin Allot
Status: Superseded
Proposed branch: ~ballot/charm-mongodb/+git/charm-mongodb:LP#1930552
Merge into: charm-mongodb:master
Prerequisite: ~ballot/charm-mongodb/+git/charm-mongodb:pytest
Diff against target: 252 lines (+108/-28)
2 files modified
files/nrpe-external-master/check_replica_sets.py (+44/-17)
tests/unit/test_check_replica_sets.py (+64/-11)
Reviewer Review Type Date Requested Status
BootStack Reviewers Pending
BootStack Reviewers Pending
Review via email: mp+414678@code.launchpad.net

This proposal has been superseded by a proposal from 2022-02-03.

Commit message

Add host and port in the replicaset check LP#1930552

The check considers that the replicaset name is the mongodb host to
check.

That is not a valid assumption, so let's parse the configuration file
and determine what it should be

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
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

Unable to determine commit message from repository - please click "Set commit message" and enter the commit message manually.

Unmerged commits

74f45e3... by Benjamin Allot

Add host and port in the replicaset check LP#1930552

The check considers that the replicaset name is the mongodb host to
check.

That is not a valid assumption, so let's parse the configuration file
and determine what it should be.

d142401... by Benjamin Allot

Use pytest instead of unittests

Because everyone deserves better looking tests output and debugging
interface.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/files/nrpe-external-master/check_replica_sets.py b/files/nrpe-external-master/check_replica_sets.py
2index f6d8feb..ec36dea 100755
3--- a/files/nrpe-external-master/check_replica_sets.py
4+++ b/files/nrpe-external-master/check_replica_sets.py
5@@ -23,6 +23,9 @@ REPL_STATES_OK = ["PRIMARY", "SECONDARY", "ARBITER"]
6 # REPL_STATES_WARN = ["STARTUP", "STARTUP2", "ROLLBACK", "RECOVERING"]
7 REPL_STATES_CRIT = ["UNKNOWN", "DOWN", "REMOVED"]
8
9+DEFAULT_BIND = "localhost"
10+DEFAULT_PORT = "27017"
11+
12
13 def get_cmd_result(cmd):
14 try:
15@@ -36,6 +39,9 @@ def get_replica_set_name():
16 # mongo2 file format the key is 'replSet'
17 # mongo34 yaml file format the key is 'replSetName'
18 # this will match both
19+ replset = False
20+ host = DEFAULT_BIND
21+ port = DEFAULT_PORT
22
23 with open("/etc/mongodb.conf", "r") as mongo_file:
24 data = mongo_file.read()
25@@ -45,19 +51,34 @@ def get_replica_set_name():
26 config = None
27
28 if isinstance(config, dict):
29- if "replication" not in config:
30- return False
31- if "replSetName" not in config["replication"]:
32- return False
33- return config["replication"]["replSetName"]
34-
35- for line in data.splitlines():
36- if line.strip().startswith("replSet") is False:
37- continue
38- parts = line.split("=")
39- return parts[1].strip()
40-
41- return False
42+ # Host and port can be avoided considering default value can be used
43+ try:
44+ host = config["net"]["bindIp"]
45+ except KeyError:
46+ pass
47+ try:
48+ port = config["net"]["port"]
49+ except KeyError:
50+ pass
51+ # Fail hard if replicaset name is absent
52+ try:
53+ replset = config["replication"]["replSetName"]
54+ except KeyError:
55+ replset = False
56+ else: # Old configuration format
57+ for line in data.splitlines():
58+ if line.strip().startswith("replSet"):
59+ replset = line.split("=")[1].strip()
60+ if line.strip().startswith("bind_ip"):
61+ host = line.split("=")[1].strip()
62+ if line.strip().startswith("port"):
63+ port = line.split("=")[1].strip()
64+
65+ # Translate 0.0.0.0 to localhost for connection purpose
66+ if host == "0.0.0.0":
67+ host = "localhost"
68+
69+ return host, port, replset
70
71
72 def get_replica_status():
73@@ -74,13 +95,19 @@ def get_replica_status():
74 # ]
75 # }
76
77- name = get_replica_set_name()
78- if not name:
79- print("CRITIAL: unable to determine the replica set name")
80+ host, port, name = get_replica_set_name()
81+ if not name or not host or not port:
82+ print("CRITICAL: unable to determine the host, port and replica set name")
83 sys.exit(NAGIOS_CRIT)
84
85 mongo_res = get_cmd_result(
86- ["/usr/bin/mongo", name, "--quiet", "--eval", "JSON.stringify(rs.status())"]
87+ [
88+ "/usr/bin/mongo",
89+ "{}:{}".format(host, port),
90+ "--quiet",
91+ "--eval",
92+ "JSON.stringify(rs.status('{}'))".format(name),
93+ ]
94 )
95
96 try:
97diff --git a/tests/unit/test_check_replica_sets.py b/tests/unit/test_check_replica_sets.py
98index 5eb9b6e..65c8def 100644
99--- a/tests/unit/test_check_replica_sets.py
100+++ b/tests/unit/test_check_replica_sets.py
101@@ -44,8 +44,30 @@ class TestCheckReplicaSets(unittest.TestCase):
102 with mock.patch(
103 "builtins.open", mock.mock_open(read_data=sample_yaml)
104 ) as mock_file:
105- res = get_replica_set_name()
106+ host, port, res = get_replica_set_name()
107 mock_file.assert_called_with("/etc/mongodb.conf", "r")
108+ self.assertEqual(host, "localhost")
109+ self.assertEqual(port, "27017")
110+ self.assertEqual(res, "test")
111+
112+ def test_get_replica_set_name_yaml_bind_and_port(self):
113+ """Test mongodb.conf file parsing replSetName success."""
114+ sample = {}
115+ sample["replication"] = {}
116+ sample["replication"]["replSetName"] = "test"
117+ sample["net"] = {
118+ "bindIp": "0.0.0.0",
119+ "port": "12345",
120+ }
121+ sample_yaml = yaml.dump(sample)
122+
123+ with mock.patch(
124+ "builtins.open", mock.mock_open(read_data=sample_yaml)
125+ ) as mock_file:
126+ host, port, res = get_replica_set_name()
127+ mock_file.assert_called_with("/etc/mongodb.conf", "r")
128+ self.assertEqual(host, "localhost")
129+ self.assertEqual(port, "12345")
130 self.assertEqual(res, "test")
131
132 def test_get_replica_set_name_yaml_no_replsetname(self):
133@@ -57,8 +79,10 @@ class TestCheckReplicaSets(unittest.TestCase):
134 with mock.patch(
135 "builtins.open", mock.mock_open(read_data=sample_yaml)
136 ) as mock_file:
137- res = get_replica_set_name()
138+ host, port, res = get_replica_set_name()
139 mock_file.assert_called_with("/etc/mongodb.conf", "r")
140+ self.assertEqual(host, "localhost")
141+ self.assertEqual(port, "27017")
142 self.assertEqual(res, False)
143
144 def test_get_replica_set_name_yaml_no_replication(self):
145@@ -70,8 +94,10 @@ class TestCheckReplicaSets(unittest.TestCase):
146 with mock.patch(
147 "builtins.open", mock.mock_open(read_data=sample_yaml)
148 ) as mock_file:
149- res = get_replica_set_name()
150+ host, port, res = get_replica_set_name()
151 mock_file.assert_called_with("/etc/mongodb.conf", "r")
152+ self.assertEqual(host, "localhost")
153+ self.assertEqual(port, "27017")
154 self.assertEqual(res, False)
155
156 def test_get_replica_set_name_ini_true(self):
157@@ -90,8 +116,10 @@ class TestCheckReplicaSets(unittest.TestCase):
158 """
159
160 with mock.patch("builtins.open", mock.mock_open(read_data=sample)) as mock_file:
161- res = get_replica_set_name()
162+ host, port, res = get_replica_set_name()
163 mock_file.assert_called_with("/etc/mongodb.conf", "r")
164+ self.assertEqual(host, "localhost")
165+ self.assertEqual(port, "27017")
166 self.assertEqual(res, "test")
167
168 def test_get_replica_set_name_ini_no_replset(self):
169@@ -109,17 +137,42 @@ class TestCheckReplicaSets(unittest.TestCase):
170 """
171
172 with mock.patch("builtins.open", mock.mock_open(read_data=sample)) as mock_file:
173- res = get_replica_set_name()
174+ host, port, res = get_replica_set_name()
175 mock_file.assert_called_with("/etc/mongodb.conf", "r")
176+ self.assertEqual(host, "localhost")
177+ self.assertEqual(port, "27017")
178 self.assertEqual(res, False)
179
180+ def test_get_replica_set_name_ini_bind0_and_nodefault_port(self):
181+ """Test mongodb.conf file missing replSet in ini format."""
182+ sample = """
183+ # mongodb.conf
184+ dbpath=/var/lib/mongodb
185+ ipv6=true
186+ logpath=/var/log/mongodb/mongodb.log
187+ logappend=true
188+ bind_ip = 0.0.0.0
189+ port = 12345
190+ journal=true
191+ diaglog = 0
192+ rest = true
193+ replSet = test
194+ """
195+
196+ with mock.patch("builtins.open", mock.mock_open(read_data=sample)) as mock_file:
197+ host, port, res = get_replica_set_name()
198+ mock_file.assert_called_with("/etc/mongodb.conf", "r")
199+ self.assertEqual(host, "localhost")
200+ self.assertEqual(port, "12345")
201+ self.assertEqual(res, "test")
202+
203 @mock.patch("check_replica_sets.get_replica_set_name", autospec=True)
204 @mock.patch("check_replica_sets.get_cmd_result", autospec=True)
205 def test_get_replica_status_ok(
206 self, mock_get_cmd_result, mock_get_replica_set_name
207 ):
208 """Test replica status in known good states gives OK."""
209- mock_get_replica_set_name.return_value = "test"
210+ mock_get_replica_set_name.return_value = "localhost", "27017", "test"
211 mock_get_cmd_result.return_value = """{
212 "set" : "myset",
213 "members" : [
214@@ -149,7 +202,7 @@ class TestCheckReplicaSets(unittest.TestCase):
215 self, mock_get_cmd_result, mock_get_replica_set_name
216 ):
217 """Test replica status in RECOVERING state gives WARN."""
218- mock_get_replica_set_name.return_value = "test"
219+ mock_get_replica_set_name.return_value = "localhost", "27017", "test"
220 mock_get_cmd_result.return_value = """{
221 "set" : "myset",
222 "members" : [
223@@ -185,7 +238,7 @@ class TestCheckReplicaSets(unittest.TestCase):
224 self, mock_get_cmd_result, mock_get_replica_set_name
225 ):
226 """Test replica status in DOWN state gives CRIT."""
227- mock_get_replica_set_name.return_value = "test"
228+ mock_get_replica_set_name.return_value = "localhost", "27017", "test"
229 mock_get_cmd_result.return_value = """{
230 "set" : "myset",
231 "members" : [
232@@ -218,9 +271,9 @@ class TestCheckReplicaSets(unittest.TestCase):
233 self, mock_get_cmd_result, mock_get_replica_set_name
234 ):
235 """Test rs.status() failure 1."""
236- mock_get_replica_set_name.return_value = False
237+ mock_get_replica_set_name.return_value = "localhost", "27017", False
238
239- result = "CRITIAL: unable to determine the replica set name\n"
240+ result = "CRITICAL: unable to determine the host, port and replica set name\n"
241 with mock.patch("sys.stdout", new=StringIO()) as fake_std_out:
242 try:
243 get_replica_status()
244@@ -234,7 +287,7 @@ class TestCheckReplicaSets(unittest.TestCase):
245 self, mock_get_cmd_result, mock_get_replica_set_name
246 ):
247 """Test rs.status() failure 2."""
248- mock_get_replica_set_name.return_value = "dont care"
249+ mock_get_replica_set_name.return_value = "localhost", "27017", "dont care"
250 mock_get_cmd_result.return_value = "{ this json is bogus }"
251
252 result = "CRITICAL: failed to load json\n"

Subscribers

People subscribed via source and target branches

to all changes: