diff --git a/lib/jnpr/junos/facts/__init__.py b/lib/jnpr/junos/facts/__init__.py index 7ac4317ae..e2013d546 100644 --- a/lib/jnpr/junos/facts/__init__.py +++ b/lib/jnpr/junos/facts/__init__.py @@ -31,7 +31,6 @@ The following dictionary keys represent the available facts and their meaning: """ - import sys import jnpr.junos.facts.current_re @@ -48,6 +47,7 @@ import jnpr.junos.facts.personality import jnpr.junos.facts.swver import jnpr.junos.facts.is_linux +import jnpr.junos.facts.vmhost def _build_fact_callbacks_and_doc_strings(): diff --git a/lib/jnpr/junos/facts/vmhost.py b/lib/jnpr/junos/facts/vmhost.py new file mode 100644 index 000000000..a2dbd5f1d --- /dev/null +++ b/lib/jnpr/junos/facts/vmhost.py @@ -0,0 +1,40 @@ +from jnpr.junos.exception import RpcError +import re +from lxml import etree + + +def provides_facts(): + """ + Returns a dictionary keyed on the facts provided by this module. The value + of each key is the doc string describing the fact. + """ + return { + "vmhost": "A boolean indicating if the device is vmhost.", + } + + +def get_facts(device): + """ + Gathers facts from the sysctl command. + """ + SYSCTL_VMHOST_MODE = "sysctl -n hw.re.vmhost_mode" + vmhost = None + + if device.facts["_is_linux"]: + vmhost = None + else: + try: + rsp = device.rpc.request_shell_execute(command=SYSCTL_VMHOST_MODE) + if rsp.tag == "rpc-error": + raise RpcError() + result = re.sub("<[^<]+>", "", etree.tostring(rsp).decode()) + if result.strip() == "1": + vmhost = True + else: + vmhost = False + except RpcError: + pass + + return { + "vmhost": vmhost, + } diff --git a/tests/unit/facts/rpc-reply/vmhost_error_request-shell-execute.xml b/tests/unit/facts/rpc-reply/vmhost_error_request-shell-execute.xml new file mode 100644 index 000000000..3e97082a6 --- /dev/null +++ b/tests/unit/facts/rpc-reply/vmhost_error_request-shell-execute.xml @@ -0,0 +1,11 @@ + + +protocol +operation-failed +error +permission denied + +system + + + diff --git a/tests/unit/facts/rpc-reply/vmhost_false_request-shell-execute.xml b/tests/unit/facts/rpc-reply/vmhost_false_request-shell-execute.xml new file mode 100644 index 000000000..d631bc6be --- /dev/null +++ b/tests/unit/facts/rpc-reply/vmhost_false_request-shell-execute.xml @@ -0,0 +1,5 @@ + + +0 + + diff --git a/tests/unit/facts/rpc-reply/vmhost_true_request-shell-execute.xml b/tests/unit/facts/rpc-reply/vmhost_true_request-shell-execute.xml new file mode 100644 index 000000000..2f5396845 --- /dev/null +++ b/tests/unit/facts/rpc-reply/vmhost_true_request-shell-execute.xml @@ -0,0 +1,5 @@ + + +1 + + diff --git a/tests/unit/facts/test_vmhost.py b/tests/unit/facts/test_vmhost.py new file mode 100644 index 000000000..d6aff5f4e --- /dev/null +++ b/tests/unit/facts/test_vmhost.py @@ -0,0 +1,74 @@ +__author__ = "Stacy Smith" +__credits__ = "Jeremy Schulman, Nitin Kumar" + +import unittest +from nose.plugins.attrib import attr +from mock import patch, MagicMock +import os + +from jnpr.junos import Device + +from ncclient.manager import Manager, make_device_handler +from ncclient.transport import SSHSession + + +@attr("unit") +class TestVmHost(unittest.TestCase): + @patch("ncclient.manager.connect") + def setUp(self, mock_connect): + mock_connect.side_effect = self._mock_manager_setup + self.dev = Device( + host="1.1.1.1", user="rick", password="password123", gather_facts=False + ) + self.dev.open() + + @patch("jnpr.junos.Device.execute") + def test_vmhost_true(self, mock_execute): + mock_execute.side_effect = self._mock_manager_vmhost_true + self.assertEqual(self.dev.facts["vmhost"], True) + + @patch("jnpr.junos.Device.execute") + def test_vmhost_false(self, mock_execute): + mock_execute.side_effect = self._mock_manager_vmhost_false + self.assertEqual(self.dev.facts["vmhost"], False) + + @patch("jnpr.junos.Device.execute") + def test_vmhost_none(self, mock_execute): + mock_execute.side_effect = self._mock_manager_vmhost_false + self.dev.facts._cache["_is_linux"] = True + self.assertEqual(self.dev.facts["vmhost"], None) + + @patch("jnpr.junos.Device.execute") + def test_vmhost_error(self, mock_execute): + mock_execute.side_effect = self._mock_manager_vmhost_error + self.assertEqual(self.dev.facts["vmhost"], None) + + def _read_file(self, fname): + from ncclient.xml_ import NCElement + + fpath = os.path.join(os.path.dirname(__file__), "rpc-reply", fname) + foo = open(fpath).read() + + rpc_reply = NCElement( + foo, self.dev._conn._device_handler.transform_reply() + )._NCElement__doc[0] + return rpc_reply + + def _mock_manager_setup(self, *args, **kwargs): + if kwargs: + device_params = kwargs["device_params"] + device_handler = make_device_handler(device_params) + session = SSHSession(device_handler) + return Manager(session, device_handler) + + def _mock_manager_vmhost_true(self, *args, **kwargs): + if args: + return self._read_file("vmhost_true_" + args[0].tag + ".xml") + + def _mock_manager_vmhost_false(self, *args, **kwargs): + if args: + return self._read_file("vmhost_false_" + args[0].tag + ".xml") + + def _mock_manager_vmhost_error(self, *args, **kwargs): + if args: + return self._read_file("vmhost_error_" + args[0].tag + ".xml")