Browse Source

Adding vg_check from the maas plugins

This change adds the volume group check from the
maas plugins, and also adds a cli helper to run bash command.

Change-Id: I303a843b0abaea721758e182a9c8f3e2db33e85d
Signed-off-by: Michael Rice <michael.rice@rackspace.com>
Signed-off-by: Kevin Carter <kevin.carter@rackspace.com>
changes/96/470196/5
Michael Rice 2 years ago
parent
commit
b676952bbe

+ 71
- 0
monitorstack/plugins/vg_check.py View File

@@ -0,0 +1,71 @@
1
+# Copyright 2017, Michael Rice <michael@michaelrice.org>
2
+#
3
+# Licensed under the Apache License, Version 2.0 (the "License");
4
+# you may not use this file except in compliance with the License.
5
+# You may obtain a copy of the License at
6
+#
7
+#     http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+# Unless required by applicable law or agreed to in writing, software
10
+# distributed under the License is distributed on an "AS IS" BASIS,
11
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+# See the License for the specific language governing permissions and
13
+# limitations under the License.
14
+
15
+import platform
16
+
17
+import click
18
+
19
+from monitorstack import utils
20
+from monitorstack.cli import pass_context
21
+from monitorstack.utils.cli import run_command
22
+
23
+DOC = """Check a given volume group"""
24
+COMMAND_NAME = 'vg_check'
25
+
26
+
27
+@click.command(COMMAND_NAME, short_help=DOC)
28
+@click.option('--volume_group', nargs=1, type=str, required=True)
29
+@pass_context
30
+def cli(ctx, volume_group):
31
+    """
32
+    Given volume group name get the total size and free space
33
+
34
+    :param ctx: Click context
35
+    :param volume_group: Name of volume group
36
+    :type volume_group: str
37
+    :return:
38
+    """
39
+    exit_code, total_size, free = check_volgrp(volume_group)
40
+    output = {
41
+        'exit_code': exit_code,
42
+        'measurement_name': COMMAND_NAME,
43
+        'meta': {
44
+            'platform': platform.platform(),
45
+        }
46
+    }
47
+    if exit_code == 0:
48
+        output['message'] = '{} check for volume group {} is ok'.format(
49
+            COMMAND_NAME, volume_group)
50
+        output['variables'] = {
51
+            'vg_{}_total_size_M'.format(volume_group): total_size,
52
+            'vg_{}_free_M'.format(volume_group): free,
53
+            'vg_{}_used_M'.format(volume_group): total_size - free
54
+        }
55
+    if exit_code != 0:
56
+        # if exit_code is not 0 then 'free' actually has our error output.
57
+        # and with py3 it is bytes so we convert to str first.
58
+        output['message'] = '{} for {} failed -- {}'.format(
59
+            COMMAND_NAME, volume_group, utils.log_exception(str(free))
60
+        )
61
+    return output
62
+
63
+
64
+def check_volgrp(name):
65
+    command = ('vgs {} --noheadings --units M '
66
+               '--nosuffix -o vg_size,vg_free'.format(name))
67
+    retcode, output, err = run_command(command)
68
+    if retcode != 0:
69
+        return retcode, output, err
70
+    totalsize, free = [int(float(x)) for x in output.split()]
71
+    return retcode, totalsize, free

+ 26
- 0
monitorstack/utils/cli.py View File

@@ -0,0 +1,26 @@
1
+# Copyright 2017, Michael Rice <michael@michaelrice.org>
2
+#
3
+# Licensed under the Apache License, Version 2.0 (the "License");
4
+# you may not use this file except in compliance with the License.
5
+# You may obtain a copy of the License at
6
+#
7
+#     http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+# Unless required by applicable law or agreed to in writing, software
10
+# distributed under the License is distributed on an "AS IS" BASIS,
11
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+# See the License for the specific language governing permissions and
13
+# limitations under the License.
14
+import shlex
15
+import subprocess
16
+
17
+
18
+def run_command(arg):
19
+    proc = subprocess.Popen(shlex.split(arg),
20
+                            stdout=subprocess.PIPE,
21
+                            stderr=subprocess.PIPE,
22
+                            shell=False)
23
+
24
+    out, err = proc.communicate()
25
+    ret = proc.returncode
26
+    return ret, out, err

+ 2
- 1
tests/__init__.py View File

@@ -31,7 +31,8 @@ def runner(module, extra_args=None):
31 31
     """
32 32
     _runner = CliRunner()
33 33
     args = [
34
-        '-f', 'json',
34
+        '-f',
35
+        'json',
35 36
         module
36 37
     ]
37 38
     if extra_args:

+ 10
- 0
tests/unit/__init__.py View File

@@ -34,3 +34,13 @@ def read_config():
34 34
 def fake_version_info(major, minor, serial):
35 35
     """Return tuple for fake python version info."""
36 36
     return major, minor, serial
37
+
38
+
39
+class FakePopen(object):
40
+    """Fake Shell Commands."""
41
+    def __init__(self, return_code=0, *args, **kwargs):
42
+        self.returncode = return_code
43
+
44
+    @staticmethod
45
+    def communicate():
46
+        return 'stdout', 'stderr'

+ 56
- 0
tests/unit/test_cli_utils.py View File

@@ -0,0 +1,56 @@
1
+# Copyright 2018, Kevin Carter <kevin@cloudnull.com>
2
+#
3
+# Licensed under the Apache License, Version 2.0 (the "License");
4
+# you may not use this file except in compliance with the License.
5
+# You may obtain a copy of the License at
6
+#
7
+#     http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+# Unless required by applicable law or agreed to in writing, software
10
+# distributed under the License is distributed on an "AS IS" BASIS,
11
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+# See the License for the specific language governing permissions and
13
+# limitations under the License.
14
+"""Tests for the cli utils plugin."""
15
+
16
+import unittest
17
+
18
+import mock
19
+
20
+from monitorstack.utils import cli
21
+
22
+import tests  # Import the test base module
23
+
24
+
25
+class TestCliUtils(unittest.TestCase):
26
+    """Tests for the utilities."""
27
+
28
+    def setUp(self):
29
+        """Setup the test."""
30
+        # load the base class for these tests.
31
+        self.communicate_patched = mock.patch(
32
+            'monitorstack.utils.cli.subprocess.Popen'
33
+        )
34
+        self.communicate = self.communicate_patched.start()
35
+
36
+    def tearDown(self):
37
+        """Tear down the test."""
38
+        self.communicate_patched.stop()
39
+
40
+    def test_run_command_success(self):
41
+        self.communicate.return_value = tests.unit.FakePopen()
42
+        ret, out, err = cli.run_command(
43
+            arg='test_command'
44
+        )
45
+        self.assertEqual(out, 'stdout')
46
+        self.assertEqual(ret, 0)
47
+
48
+    def test_run_command_fail(self):
49
+        self.communicate.return_value = tests.unit.FakePopen(
50
+            return_code=1
51
+        )
52
+        ret, out, err = cli.run_command(
53
+            arg='test_command'
54
+        )
55
+        self.assertEqual(err, 'stderr')
56
+        self.assertEqual(ret, 1)

+ 1
- 15
tests/unit/test_plugin_kvm.py View File

@@ -13,26 +13,12 @@
13 13
 # limitations under the License.
14 14
 """Tests for the KVM plugin."""
15 15
 
16
-import json
17 16
 import sys
18 17
 import unittest
19 18
 
20
-from click.testing import CliRunner
21
-
22
-from monitorstack.cli import cli
23
-
24 19
 import tests.unit  # Import the test base module
25 20
 
26 21
 
27
-def _runner(module):
28
-    runner = CliRunner()
29
-    result = runner.invoke(cli, ['-f', 'json', module])
30
-    try:
31
-        return json.loads(result.output)
32
-    except Exception:
33
-        return result.exception
34
-
35
-
36 22
 class LibvirtStub(object):
37 23
     """Stubbed libvirt class."""
38 24
 
@@ -91,7 +77,7 @@ class TestKvm(unittest.TestCase):
91 77
 
92 78
     def test_run_success(self):
93 79
         """Ensure the run() method works."""
94
-        result = _runner('kvm')
80
+        result = tests.runner('kvm')
95 81
         variables = result['variables']
96 82
         meta = result['meta']
97 83
         assert 'kvm_vms' in variables

+ 76
- 0
tests/unit/test_plugin_vg_check.py View File

@@ -0,0 +1,76 @@
1
+# Copyright 2017, Michael Rice <michael@michaelrice.org>
2
+#
3
+# Licensed under the Apache License, Version 2.0 (the "License");
4
+# you may not use this file except in compliance with the License.
5
+# You may obtain a copy of the License at
6
+#
7
+#     http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+# Unless required by applicable law or agreed to in writing, software
10
+# distributed under the License is distributed on an "AS IS" BASIS,
11
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+# See the License for the specific language governing permissions and
13
+# limitations under the License.
14
+
15
+import unittest
16
+
17
+import mock
18
+
19
+from monitorstack.plugins import vg_check
20
+
21
+import tests.unit  # Import the test base module
22
+
23
+
24
+class VolumeGroupTestCases(unittest.TestCase):
25
+
26
+    def setUp(self):
27
+        """Setup the test."""
28
+        # load the base class for these tests.
29
+        self.communicate_patched = mock.patch(
30
+            'monitorstack.utils.cli.subprocess.Popen'
31
+        )
32
+        self.communicate = self.communicate_patched.start()
33
+
34
+    def tearDown(self):
35
+        """Tear down the test."""
36
+        self.communicate_patched.stop()
37
+
38
+    @mock.patch("monitorstack.utils.cli.subprocess")
39
+    def test_check_volgrp_returns_with_vg_not_found(self, mock_path):
40
+        """
41
+        When the volume group is not found an exit status code of 5 is
42
+        returned by the system. When a non 0 is returned the expected
43
+        result from this call is is an error message with a blank total
44
+        """
45
+        mock_path.Popen.return_value.returncode = 5
46
+        mock_path.Popen.return_value.communicate.return_value = \
47
+            ("", "Volume group foo not found")
48
+        ret_code, total, free = vg_check.check_volgrp("foo")
49
+        assert ret_code == 5
50
+        assert total == ""
51
+        assert free == "Volume group foo not found"
52
+
53
+
54
+class TestVolumeGroup(object):
55
+    def test_cli_would_exec_command(self, monkeypatch):
56
+        def mock_get_vgs(name):
57
+            """Mock the check_volgrp() method."""
58
+            return 0, 100, 99
59
+
60
+        monkeypatch.setattr(
61
+            vg_check,
62
+            'check_volgrp',
63
+            mock_get_vgs
64
+        )
65
+
66
+        result = tests.runner(
67
+            'vg_check',
68
+            extra_args=['--volume_group', 'test']
69
+        )
70
+        variables = result['variables']
71
+        assert 'vg_test_used_M' in variables
72
+        assert variables['vg_test_used_M'] == 1
73
+        assert 'vg_test_free_M' in variables
74
+        assert variables['vg_test_free_M'] == 99
75
+        assert 'vg_test_total_size_M' in variables
76
+        assert variables['vg_test_total_size_M'] == 100

Loading…
Cancel
Save