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 @@
+
+
+
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 @@
+
+
+
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")