Browse Source

Make generic OCObjectValidator from OCSDNValidator

Signed-off-by: Monis Khan <mkhan@redhat.com>
Monis Khan 8 years ago
parent
commit
66cc0be1dc

+ 45 - 26
roles/lib_openshift/library/oc_sdnvalidator.py

@@ -50,14 +50,14 @@ from ansible.module_utils.basic import AnsibleModule
 
 # -*- -*- -*- End included fragment: lib/import.py -*- -*- -*-
 
-# -*- -*- -*- Begin included fragment: doc/sdnvalidator -*- -*- -*-
+# -*- -*- -*- Begin included fragment: doc/objectvalidator -*- -*- -*-
 
 DOCUMENTATION = '''
 ---
-module: oc_sdnvalidator
-short_description: Validate SDN objects
+module: oc_objectvalidator
+short_description: Validate OpenShift objects
 description:
-  - Validate SDN objects
+  - Validate OpenShift objects
 options:
   kubeconfig:
     description:
@@ -71,13 +71,13 @@ extends_documentation_fragment: []
 '''
 
 EXAMPLES = '''
-oc_version:
-- name: get oc sdnvalidator
-  sdnvalidator:
-  register: oc_sdnvalidator
+oc_objectvalidator:
+- name: run oc_objectvalidator
+  oc_objectvalidator:
+  register: oc_objectvalidator
 '''
 
-# -*- -*- -*- End included fragment: doc/sdnvalidator -*- -*- -*-
+# -*- -*- -*- End included fragment: doc/objectvalidator -*- -*- -*-
 
 # -*- -*- -*- Begin included fragment: ../../lib_utils/src/class/yedit.py -*- -*- -*-
 # pylint: disable=undefined-variable,missing-docstring
@@ -1307,25 +1307,25 @@ class OpenShiftCLIConfig(object):
 
 # -*- -*- -*- End included fragment: lib/base.py -*- -*- -*-
 
-# -*- -*- -*- Begin included fragment: class/oc_sdnvalidator.py -*- -*- -*-
+# -*- -*- -*- Begin included fragment: class/oc_objectvalidator.py -*- -*- -*-
 
 # pylint: disable=too-many-instance-attributes
-class OCSDNValidator(OpenShiftCLI):
+class OCObjectValidator(OpenShiftCLI):
     ''' Class to wrap the oc command line tools '''
 
     def __init__(self, kubeconfig):
-        ''' Constructor for OCSDNValidator '''
-        # namespace has no meaning for SDN validation, hardcode to 'default'
-        super(OCSDNValidator, self).__init__('default', kubeconfig)
+        ''' Constructor for OCObjectValidator '''
+        # namespace has no meaning for object validation, hardcode to 'default'
+        super(OCObjectValidator, self).__init__('default', kubeconfig)
 
-    def get(self, kind, invalid_filter):
-        ''' return SDN information '''
+    def get_invalid(self, kind, invalid_filter):
+        ''' return invalid object information '''
 
         rval = self._get(kind)
         if rval['returncode'] != 0:
             return False, rval, []
 
-        return True, rval, filter(invalid_filter, rval['results'][0]['items'])
+        return True, rval, list(filter(invalid_filter, rval['results'][0]['items']))  # wrap filter with list for py3
 
     # pylint: disable=too-many-return-statements
     @staticmethod
@@ -1335,10 +1335,24 @@ class OCSDNValidator(OpenShiftCLI):
             params comes from the ansible portion of this module
         '''
 
-        sdnvalidator = OCSDNValidator(params['kubeconfig'])
+        objectvalidator = OCObjectValidator(params['kubeconfig'])
         all_invalid = {}
         failed = False
 
+        def _is_invalid_namespace(namespace):
+            # check if it uses a reserved name
+            name = namespace['metadata']['name']
+            if not any((name == 'kube',
+                        name == 'openshift',
+                        name.startswith('kube-'),
+                        name.startswith('openshift-'),)):
+                return False
+
+            # determine if the namespace was created by a user
+            if 'annotations' not in namespace['metadata']:
+                return False
+            return 'openshift.io/requester' in namespace['metadata']['annotations']
+
         checks = (
             (
                 'hostsubnet',
@@ -1350,10 +1364,15 @@ class OCSDNValidator(OpenShiftCLI):
                 lambda x: x['metadata']['name'] != x['netname'],
                 u'netnamespaces where metadata.name != netname',
             ),
+            (
+                'namespace',
+                _is_invalid_namespace,
+                u'namespaces that use reserved names and were not created by infrastructure components',
+            ),
         )
 
         for resource, invalid_filter, invalid_msg in checks:
-            success, rval, invalid = sdnvalidator.get(resource, invalid_filter)
+            success, rval, invalid = objectvalidator.get_invalid(resource, invalid_filter)
             if not success:
                 return {'failed': True, 'msg': 'Failed to GET {}.'.format(resource), 'state': 'list', 'results': rval}
             if invalid:
@@ -1361,17 +1380,17 @@ class OCSDNValidator(OpenShiftCLI):
                 all_invalid[invalid_msg] = invalid
 
         if failed:
-            return {'failed': True, 'msg': 'All SDN objects are not valid.', 'state': 'list', 'results': all_invalid}
+            return {'failed': True, 'msg': 'All objects are not valid.', 'state': 'list', 'results': all_invalid}
 
-        return {'msg': 'All SDN objects are valid.'}
+        return {'msg': 'All objects are valid.'}
 
-# -*- -*- -*- End included fragment: class/oc_sdnvalidator.py -*- -*- -*-
+# -*- -*- -*- End included fragment: class/oc_objectvalidator.py -*- -*- -*-
 
-# -*- -*- -*- Begin included fragment: ansible/oc_sdnvalidator.py -*- -*- -*-
+# -*- -*- -*- Begin included fragment: ansible/oc_objectvalidator.py -*- -*- -*-
 
 def main():
     '''
-    ansible oc module for validating OpenShift SDN objects
+    ansible oc module for validating OpenShift objects
     '''
 
     module = AnsibleModule(
@@ -1382,7 +1401,7 @@ def main():
     )
 
 
-    rval = OCSDNValidator.run_ansible(module.params)
+    rval = OCObjectValidator.run_ansible(module.params)
     if 'failed' in rval:
         module.fail_json(**rval)
 
@@ -1391,4 +1410,4 @@ def main():
 if __name__ == '__main__':
     main()
 
-# -*- -*- -*- End included fragment: ansible/oc_sdnvalidator.py -*- -*- -*-
+# -*- -*- -*- End included fragment: ansible/oc_objectvalidator.py -*- -*- -*-

+ 2 - 2
roles/lib_openshift/src/ansible/oc_sdnvalidator.py

@@ -3,7 +3,7 @@
 
 def main():
     '''
-    ansible oc module for validating OpenShift SDN objects
+    ansible oc module for validating OpenShift objects
     '''
 
     module = AnsibleModule(
@@ -14,7 +14,7 @@ def main():
     )
 
 
-    rval = OCSDNValidator.run_ansible(module.params)
+    rval = OCObjectValidator.run_ansible(module.params)
     if 'failed' in rval:
         module.fail_json(**rval)
 

+ 77 - 0
roles/lib_openshift/src/class/oc_objectvalidator.py

@@ -0,0 +1,77 @@
+# pylint: skip-file
+# flake8: noqa
+
+# pylint: disable=too-many-instance-attributes
+class OCObjectValidator(OpenShiftCLI):
+    ''' Class to wrap the oc command line tools '''
+
+    def __init__(self, kubeconfig):
+        ''' Constructor for OCObjectValidator '''
+        # namespace has no meaning for object validation, hardcode to 'default'
+        super(OCObjectValidator, self).__init__('default', kubeconfig)
+
+    def get_invalid(self, kind, invalid_filter):
+        ''' return invalid object information '''
+
+        rval = self._get(kind)
+        if rval['returncode'] != 0:
+            return False, rval, []
+
+        return True, rval, list(filter(invalid_filter, rval['results'][0]['items']))  # wrap filter with list for py3
+
+    # pylint: disable=too-many-return-statements
+    @staticmethod
+    def run_ansible(params):
+        ''' run the idempotent ansible code
+
+            params comes from the ansible portion of this module
+        '''
+
+        objectvalidator = OCObjectValidator(params['kubeconfig'])
+        all_invalid = {}
+        failed = False
+
+        def _is_invalid_namespace(namespace):
+            # check if it uses a reserved name
+            name = namespace['metadata']['name']
+            if not any((name == 'kube',
+                        name == 'openshift',
+                        name.startswith('kube-'),
+                        name.startswith('openshift-'),)):
+                return False
+
+            # determine if the namespace was created by a user
+            if 'annotations' not in namespace['metadata']:
+                return False
+            return 'openshift.io/requester' in namespace['metadata']['annotations']
+
+        checks = (
+            (
+                'hostsubnet',
+                lambda x: x['metadata']['name'] != x['host'],
+                u'hostsubnets where metadata.name != host',
+            ),
+            (
+                'netnamespace',
+                lambda x: x['metadata']['name'] != x['netname'],
+                u'netnamespaces where metadata.name != netname',
+            ),
+            (
+                'namespace',
+                _is_invalid_namespace,
+                u'namespaces that use reserved names and were not created by infrastructure components',
+            ),
+        )
+
+        for resource, invalid_filter, invalid_msg in checks:
+            success, rval, invalid = objectvalidator.get_invalid(resource, invalid_filter)
+            if not success:
+                return {'failed': True, 'msg': 'Failed to GET {}.'.format(resource), 'state': 'list', 'results': rval}
+            if invalid:
+                failed = True
+                all_invalid[invalid_msg] = invalid
+
+        if failed:
+            return {'failed': True, 'msg': 'All objects are not valid.', 'state': 'list', 'results': all_invalid}
+
+        return {'msg': 'All objects are valid.'}

+ 0 - 58
roles/lib_openshift/src/class/oc_sdnvalidator.py

@@ -1,58 +0,0 @@
-# pylint: skip-file
-# flake8: noqa
-
-# pylint: disable=too-many-instance-attributes
-class OCSDNValidator(OpenShiftCLI):
-    ''' Class to wrap the oc command line tools '''
-
-    def __init__(self, kubeconfig):
-        ''' Constructor for OCSDNValidator '''
-        # namespace has no meaning for SDN validation, hardcode to 'default'
-        super(OCSDNValidator, self).__init__('default', kubeconfig)
-
-    def get(self, kind, invalid_filter):
-        ''' return SDN information '''
-
-        rval = self._get(kind)
-        if rval['returncode'] != 0:
-            return False, rval, []
-
-        return True, rval, filter(invalid_filter, rval['results'][0]['items'])
-
-    # pylint: disable=too-many-return-statements
-    @staticmethod
-    def run_ansible(params):
-        ''' run the idempotent ansible code
-
-            params comes from the ansible portion of this module
-        '''
-
-        sdnvalidator = OCSDNValidator(params['kubeconfig'])
-        all_invalid = {}
-        failed = False
-
-        checks = (
-            (
-                'hostsubnet',
-                lambda x: x['metadata']['name'] != x['host'],
-                u'hostsubnets where metadata.name != host',
-            ),
-            (
-                'netnamespace',
-                lambda x: x['metadata']['name'] != x['netname'],
-                u'netnamespaces where metadata.name != netname',
-            ),
-        )
-
-        for resource, invalid_filter, invalid_msg in checks:
-            success, rval, invalid = sdnvalidator.get(resource, invalid_filter)
-            if not success:
-                return {'failed': True, 'msg': 'Failed to GET {}.'.format(resource), 'state': 'list', 'results': rval}
-            if invalid:
-                failed = True
-                all_invalid[invalid_msg] = invalid
-
-        if failed:
-            return {'failed': True, 'msg': 'All SDN objects are not valid.', 'state': 'list', 'results': all_invalid}
-
-        return {'msg': 'All SDN objects are valid.'}

+ 7 - 7
roles/lib_openshift/src/doc/sdnvalidator

@@ -3,10 +3,10 @@
 
 DOCUMENTATION = '''
 ---
-module: oc_sdnvalidator
-short_description: Validate SDN objects
+module: oc_objectvalidator
+short_description: Validate OpenShift objects
 description:
-  - Validate SDN objects
+  - Validate OpenShift objects
 options:
   kubeconfig:
     description:
@@ -20,8 +20,8 @@ extends_documentation_fragment: []
 '''
 
 EXAMPLES = '''
-oc_version:
-- name: get oc sdnvalidator
-  sdnvalidator:
-  register: oc_sdnvalidator
+oc_objectvalidator:
+- name: run oc_objectvalidator
+  oc_objectvalidator:
+  register: oc_objectvalidator
 '''

+ 4 - 4
roles/lib_openshift/src/sources.yml

@@ -218,12 +218,12 @@ oc_version.py:
 - class/oc_version.py
 - ansible/oc_version.py
 
-oc_sdnvalidator.py:
+oc_objectvalidator.py:
 - doc/generated
 - doc/license
 - lib/import.py
-- doc/sdnvalidator
+- doc/objectvalidator
 - ../../lib_utils/src/class/yedit.py
 - lib/base.py
-- class/oc_sdnvalidator.py
-- ansible/oc_sdnvalidator.py
+- class/oc_objectvalidator.py
+- ansible/oc_objectvalidator.py

+ 0 - 481
roles/lib_openshift/src/test/unit/oc_sdnvalidator.py

@@ -1,481 +0,0 @@
-#!/usr/bin/env python2
-'''
- Unit tests for oc sdnvalidator
-'''
-# To run
-# ./oc_sdnvalidator.py
-#
-# ....
-# ----------------------------------------------------------------------
-# Ran 4 tests in 0.002s
-#
-# OK
-
-import os
-import sys
-import unittest
-import mock
-
-# Removing invalid variable names for tests so that I can
-# keep them brief
-# pylint: disable=invalid-name,no-name-in-module
-# Disable import-error b/c our libraries aren't loaded in jenkins
-# pylint: disable=import-error
-# place class in our python path
-module_path = os.path.join('/'.join(os.path.realpath(__file__).split('/')[:-4]), 'library')  # noqa: E501
-sys.path.insert(0, module_path)
-from oc_sdnvalidator import OCSDNValidator  # noqa: E402
-
-
-class OCSDNValidatorTest(unittest.TestCase):
-    '''
-     Test class for OCSDNValidator
-    '''
-
-    @mock.patch('oc_sdnvalidator.Utils.create_tmpfile_copy')
-    @mock.patch('oc_sdnvalidator.OCSDNValidator._run')
-    def test_no_data(self, mock_cmd, mock_tmpfile_copy):
-        ''' Testing when both SDN objects are empty '''
-
-        # Arrange
-
-        # run_ansible input parameters
-        params = {
-            'kubeconfig': '/etc/origin/master/admin.kubeconfig',
-        }
-
-        empty = '''{
-    "apiVersion": "v1",
-    "items": [],
-    "kind": "List",
-    "metadata": {},
-    "resourceVersion": "",
-    "selfLink": ""
-}'''
-
-        # Return values of our mocked function call. These get returned once per call.
-        mock_cmd.side_effect = [
-            # First call to mock
-            (0, empty, ''),
-
-            # Second call to mock
-            (0, empty, ''),
-        ]
-
-        mock_tmpfile_copy.side_effect = [
-            '/tmp/mocked_kubeconfig',
-        ]
-
-        # Act
-        results = OCSDNValidator.run_ansible(params)
-
-        # Assert
-        self.assertNotIn('failed', results)
-        self.assertEqual(results['msg'], 'All SDN objects are valid.')
-
-        # Making sure our mock was called as we expected
-        mock_cmd.assert_has_calls([
-            mock.call(['oc', '-n', 'default', 'get', 'hostsubnet', '-o', 'json'], None),
-            mock.call(['oc', '-n', 'default', 'get', 'netnamespace', '-o', 'json'], None),
-        ])
-
-    @mock.patch('oc_sdnvalidator.Utils.create_tmpfile_copy')
-    @mock.patch('oc_sdnvalidator.OCSDNValidator._run')
-    def test_error_code(self, mock_cmd, mock_tmpfile_copy):
-        ''' Testing when both we fail to get SDN objects '''
-
-        # Arrange
-
-        # run_ansible input parameters
-        params = {
-            'kubeconfig': '/etc/origin/master/admin.kubeconfig',
-        }
-
-        # Return values of our mocked function call. These get returned once per call.
-        mock_cmd.side_effect = [
-            # First call to mock
-            (1, '', 'Error.'),
-        ]
-
-        mock_tmpfile_copy.side_effect = [
-            '/tmp/mocked_kubeconfig',
-        ]
-
-        error_results = {
-            'returncode': 1,
-            'stderr': 'Error.',
-            'stdout': '',
-            'cmd': 'oc -n default get hostsubnet -o json',
-            'results': [{}]
-        }
-
-        # Act
-        results = OCSDNValidator.run_ansible(params)
-
-        # Assert
-        self.assertTrue(results['failed'])
-        self.assertEqual(results['msg'], 'Failed to GET hostsubnet.')
-        self.assertEqual(results['state'], 'list')
-        self.assertEqual(results['results'], error_results)
-
-        # Making sure our mock was called as we expected
-        mock_cmd.assert_has_calls([
-            mock.call(['oc', '-n', 'default', 'get', 'hostsubnet', '-o', 'json'], None),
-        ])
-
-    @mock.patch('oc_sdnvalidator.Utils.create_tmpfile_copy')
-    @mock.patch('oc_sdnvalidator.OCSDNValidator._run')
-    def test_valid_both(self, mock_cmd, mock_tmpfile_copy):
-        ''' Testing when both SDN objects are valid '''
-
-        # Arrange
-
-        # run_ansible input parameters
-        params = {
-            'kubeconfig': '/etc/origin/master/admin.kubeconfig',
-        }
-
-        valid_hostsubnet = '''{
-    "apiVersion": "v1",
-    "items": [
-        {
-            "apiVersion": "v1",
-            "host": "bar0",
-            "hostIP": "1.1.1.1",
-            "kind": "HostSubnet",
-            "metadata": {
-                "creationTimestamp": "2017-02-16T18:47:09Z",
-                "name": "bar0",
-                "namespace": "",
-                "resourceVersion": "986",
-                "selfLink": "/oapi/v1/hostsubnetsbar0",
-                "uid": "528dbb41-f478-11e6-aae0-507b9dac97ff"
-            },
-            "subnet": "1.1.0.0/24"
-        },
-        {
-            "apiVersion": "v1",
-            "host": "bar1",
-            "hostIP": "1.1.1.1",
-            "kind": "HostSubnet",
-            "metadata": {
-                "creationTimestamp": "2017-02-16T18:47:18Z",
-                "name": "bar1",
-                "namespace": "",
-                "resourceVersion": "988",
-                "selfLink": "/oapi/v1/hostsubnetsbar1",
-                "uid": "57710d84-f478-11e6-aae0-507b9dac97ff"
-            },
-            "subnet": "1.1.0.0/24"
-        },
-        {
-            "apiVersion": "v1",
-            "host": "bar2",
-            "hostIP": "1.1.1.1",
-            "kind": "HostSubnet",
-            "metadata": {
-                "creationTimestamp": "2017-02-16T18:47:26Z",
-                "name": "bar2",
-                "namespace": "",
-                "resourceVersion": "991",
-                "selfLink": "/oapi/v1/hostsubnetsbar2",
-                "uid": "5c59a28c-f478-11e6-aae0-507b9dac97ff"
-            },
-            "subnet": "1.1.0.0/24"
-        }
-    ],
-    "kind": "List",
-    "metadata": {},
-    "resourceVersion": "",
-    "selfLink": ""
-    }'''
-
-        valid_netnamespace = '''{
-    "apiVersion": "v1",
-    "items": [
-        {
-            "apiVersion": "v1",
-            "kind": "NetNamespace",
-            "metadata": {
-                "creationTimestamp": "2017-02-16T18:45:16Z",
-                "name": "foo0",
-                "namespace": "",
-                "resourceVersion": "959",
-                "selfLink": "/oapi/v1/netnamespacesfoo0",
-                "uid": "0f1c85b2-f478-11e6-aae0-507b9dac97ff"
-            },
-            "netid": 100,
-            "netname": "foo0"
-        },
-        {
-            "apiVersion": "v1",
-            "kind": "NetNamespace",
-            "metadata": {
-                "creationTimestamp": "2017-02-16T18:45:26Z",
-                "name": "foo1",
-                "namespace": "",
-                "resourceVersion": "962",
-                "selfLink": "/oapi/v1/netnamespacesfoo1",
-                "uid": "14effa0d-f478-11e6-aae0-507b9dac97ff"
-            },
-            "netid": 100,
-            "netname": "foo1"
-        },
-        {
-            "apiVersion": "v1",
-            "kind": "NetNamespace",
-            "metadata": {
-                "creationTimestamp": "2017-02-16T18:45:36Z",
-                "name": "foo2",
-                "namespace": "",
-                "resourceVersion": "965",
-                "selfLink": "/oapi/v1/netnamespacesfoo2",
-                "uid": "1aabdf84-f478-11e6-aae0-507b9dac97ff"
-            },
-            "netid": 100,
-            "netname": "foo2"
-        }
-    ],
-    "kind": "List",
-    "metadata": {},
-    "resourceVersion": "",
-    "selfLink": ""
-    }'''
-
-        # Return values of our mocked function call. These get returned once per call.
-        mock_cmd.side_effect = [
-            # First call to mock
-            (0, valid_hostsubnet, ''),
-
-            # Second call to mock
-            (0, valid_netnamespace, ''),
-        ]
-
-        mock_tmpfile_copy.side_effect = [
-            '/tmp/mocked_kubeconfig',
-        ]
-
-        # Act
-        results = OCSDNValidator.run_ansible(params)
-
-        # Assert
-        self.assertNotIn('failed', results)
-        self.assertEqual(results['msg'], 'All SDN objects are valid.')
-
-        # Making sure our mock was called as we expected
-        mock_cmd.assert_has_calls([
-            mock.call(['oc', '-n', 'default', 'get', 'hostsubnet', '-o', 'json'], None),
-            mock.call(['oc', '-n', 'default', 'get', 'netnamespace', '-o', 'json'], None),
-        ])
-
-    @mock.patch('oc_sdnvalidator.Utils.create_tmpfile_copy')
-    @mock.patch('oc_sdnvalidator.OCSDNValidator._run')
-    def test_invalid_both(self, mock_cmd, mock_tmpfile_copy):
-        ''' Testing when both SDN objects are invalid '''
-
-        # Arrange
-
-        # run_ansible input parameters
-        params = {
-            'kubeconfig': '/etc/origin/master/admin.kubeconfig',
-        }
-
-        invalid_hostsubnet = '''{
-    "apiVersion": "v1",
-    "items": [
-        {
-            "apiVersion": "v1",
-            "host": "bar0",
-            "hostIP": "1.1.1.1",
-            "kind": "HostSubnet",
-            "metadata": {
-                "creationTimestamp": "2017-02-16T18:47:09Z",
-                "name": "bar0",
-                "namespace": "",
-                "resourceVersion": "986",
-                "selfLink": "/oapi/v1/hostsubnetsbar0",
-                "uid": "528dbb41-f478-11e6-aae0-507b9dac97ff"
-            },
-            "subnet": "1.1.0.0/24"
-        },
-        {
-            "apiVersion": "v1",
-            "host": "bar1",
-            "hostIP": "1.1.1.1",
-            "kind": "HostSubnet",
-            "metadata": {
-                "creationTimestamp": "2017-02-16T18:47:18Z",
-                "name": "bar1",
-                "namespace": "",
-                "resourceVersion": "988",
-                "selfLink": "/oapi/v1/hostsubnetsbar1",
-                "uid": "57710d84-f478-11e6-aae0-507b9dac97ff"
-            },
-            "subnet": "1.1.0.0/24"
-        },
-        {
-            "apiVersion": "v1",
-            "host": "bar2",
-            "hostIP": "1.1.1.1",
-            "kind": "HostSubnet",
-            "metadata": {
-                "creationTimestamp": "2017-02-16T18:47:26Z",
-                "name": "bar2",
-                "namespace": "",
-                "resourceVersion": "991",
-                "selfLink": "/oapi/v1/hostsubnetsbar2",
-                "uid": "5c59a28c-f478-11e6-aae0-507b9dac97ff"
-            },
-            "subnet": "1.1.0.0/24"
-        },
-        {
-            "apiVersion": "v1",
-            "host": "baz1",
-            "hostIP": "1.1.1.1",
-            "kind": "HostSubnet",
-            "metadata": {
-                "creationTimestamp": "2017-02-16T18:47:49Z",
-                "name": "baz0",
-                "namespace": "",
-                "resourceVersion": "996",
-                "selfLink": "/oapi/v1/hostsubnetsbaz0",
-                "uid": "69f75f87-f478-11e6-aae0-507b9dac97ff"
-            },
-            "subnet": "1.1.0.0/24"
-        }
-    ],
-    "kind": "List",
-    "metadata": {},
-    "resourceVersion": "",
-    "selfLink": ""
-}'''
-
-        invalid_netnamespace = '''{
-    "apiVersion": "v1",
-    "items": [
-        {
-            "apiVersion": "v1",
-            "kind": "NetNamespace",
-            "metadata": {
-                "creationTimestamp": "2017-02-16T18:45:52Z",
-                "name": "bar0",
-                "namespace": "",
-                "resourceVersion": "969",
-                "selfLink": "/oapi/v1/netnamespacesbar0",
-                "uid": "245d416e-f478-11e6-aae0-507b9dac97ff"
-            },
-            "netid": 100,
-            "netname": "bar1"
-        },
-        {
-            "apiVersion": "v1",
-            "kind": "NetNamespace",
-            "metadata": {
-                "creationTimestamp": "2017-02-16T18:45:16Z",
-                "name": "foo0",
-                "namespace": "",
-                "resourceVersion": "959",
-                "selfLink": "/oapi/v1/netnamespacesfoo0",
-                "uid": "0f1c85b2-f478-11e6-aae0-507b9dac97ff"
-            },
-            "netid": 100,
-            "netname": "foo0"
-        },
-        {
-            "apiVersion": "v1",
-            "kind": "NetNamespace",
-            "metadata": {
-                "creationTimestamp": "2017-02-16T18:45:26Z",
-                "name": "foo1",
-                "namespace": "",
-                "resourceVersion": "962",
-                "selfLink": "/oapi/v1/netnamespacesfoo1",
-                "uid": "14effa0d-f478-11e6-aae0-507b9dac97ff"
-            },
-            "netid": 100,
-            "netname": "foo1"
-        },
-        {
-            "apiVersion": "v1",
-            "kind": "NetNamespace",
-            "metadata": {
-                "creationTimestamp": "2017-02-16T18:45:36Z",
-                "name": "foo2",
-                "namespace": "",
-                "resourceVersion": "965",
-                "selfLink": "/oapi/v1/netnamespacesfoo2",
-                "uid": "1aabdf84-f478-11e6-aae0-507b9dac97ff"
-            },
-            "netid": 100,
-            "netname": "foo2"
-        }
-    ],
-    "kind": "List",
-    "metadata": {},
-    "resourceVersion": "",
-    "selfLink": ""
-}'''
-
-        invalid_results = {
-            'hostsubnets where metadata.name != host': [{
-                'apiVersion': 'v1',
-                'host': 'baz1',
-                'hostIP': '1.1.1.1',
-                'kind': 'HostSubnet',
-                'metadata': {
-                    'creationTimestamp': '2017-02-16T18:47:49Z',
-                    'name': 'baz0',
-                    'namespace': '',
-                    'resourceVersion': '996',
-                    'selfLink': '/oapi/v1/hostsubnetsbaz0',
-                    'uid': '69f75f87-f478-11e6-aae0-507b9dac97ff'
-                },
-                'subnet': '1.1.0.0/24'
-            }],
-            'netnamespaces where metadata.name != netname': [{
-                'apiVersion': 'v1',
-                'kind': 'NetNamespace',
-                'metadata': {
-                    'creationTimestamp': '2017-02-16T18:45:52Z',
-                    'name': 'bar0',
-                    'namespace': '',
-                    'resourceVersion': '969',
-                    'selfLink': '/oapi/v1/netnamespacesbar0',
-                    'uid': '245d416e-f478-11e6-aae0-507b9dac97ff'
-                },
-                'netid': 100,
-                'netname': 'bar1'
-            }],
-        }
-
-        # Return values of our mocked function call. These get returned once per call.
-        mock_cmd.side_effect = [
-            # First call to mock
-            (0, invalid_hostsubnet, ''),
-
-            # Second call to mock
-            (0, invalid_netnamespace, ''),
-        ]
-
-        mock_tmpfile_copy.side_effect = [
-            '/tmp/mocked_kubeconfig',
-        ]
-
-        # Act
-        results = OCSDNValidator.run_ansible(params)
-
-        # Assert
-        self.assertTrue(results['failed'])
-        self.assertEqual(results['msg'], 'All SDN objects are not valid.')
-        self.assertEqual(results['state'], 'list')
-        self.assertEqual(results['results'], invalid_results)
-
-        # Making sure our mock was called as we expected
-        mock_cmd.assert_has_calls([
-            mock.call(['oc', '-n', 'default', 'get', 'hostsubnet', '-o', 'json'], None),
-            mock.call(['oc', '-n', 'default', 'get', 'netnamespace', '-o', 'json'], None),
-        ])
-
-
-if __name__ == '__main__':
-    unittest.main()

+ 916 - 0
roles/lib_openshift/src/test/unit/test_oc_objectvalidator.py

@@ -0,0 +1,916 @@
+#!/usr/bin/env python2
+'''
+ Unit tests for oc_objectvalidator
+'''
+# To run
+# ./oc_objectvalidator.py.py
+#
+# ....
+# ----------------------------------------------------------------------
+# Ran 4 tests in 0.002s
+#
+# OK
+
+import os
+import sys
+import unittest
+import mock
+
+# Removing invalid variable names for tests so that I can
+# keep them brief
+# pylint: disable=invalid-name,no-name-in-module
+# Disable import-error b/c our libraries aren't loaded in jenkins
+# pylint: disable=import-error
+# place class in our python path
+module_path = os.path.join('/'.join(os.path.realpath(__file__).split('/')[:-4]), 'library')  # noqa: E501
+sys.path.insert(0, module_path)
+from oc_objectvalidator import OCObjectValidator  # noqa: E402
+
+
+class OCObjectValidatorTest(unittest.TestCase):
+    '''
+     Test class for OCObjectValidator
+    '''
+
+    maxDiff = None
+
+    @mock.patch('oc_objectvalidator.Utils.create_tmpfile_copy')
+    @mock.patch('oc_objectvalidator.OCObjectValidator._run')
+    def test_no_data(self, mock_cmd, mock_tmpfile_copy):
+        ''' Testing when both all objects are empty '''
+
+        # Arrange
+
+        # run_ansible input parameters
+        params = {
+            'kubeconfig': '/etc/origin/master/admin.kubeconfig',
+        }
+
+        empty = '''{
+    "apiVersion": "v1",
+    "items": [],
+    "kind": "List",
+    "metadata": {},
+    "resourceVersion": "",
+    "selfLink": ""
+}'''
+
+        # Return values of our mocked function call. These get returned once per call.
+        mock_cmd.side_effect = [
+            # First call to mock
+            (0, empty, ''),
+
+            # Second call to mock
+            (0, empty, ''),
+
+            # Third call to mock
+            (0, empty, ''),
+        ]
+
+        mock_tmpfile_copy.side_effect = [
+            '/tmp/mocked_kubeconfig',
+        ]
+
+        # Act
+        results = OCObjectValidator.run_ansible(params)
+
+        # Assert
+        self.assertNotIn('failed', results)
+        self.assertEqual(results['msg'], 'All objects are valid.')
+
+        # Making sure our mock was called as we expected
+        mock_cmd.assert_has_calls([
+            mock.call(['oc', 'get', 'hostsubnet', '-o', 'json', '-n', 'default'], None),
+            mock.call(['oc', 'get', 'netnamespace', '-o', 'json', '-n', 'default'], None),
+            mock.call(['oc', 'get', 'namespace', '-o', 'json', '-n', 'default'], None),
+        ])
+
+    @mock.patch('oc_objectvalidator.Utils.create_tmpfile_copy')
+    @mock.patch('oc_objectvalidator.OCObjectValidator._run')
+    def test_error_code(self, mock_cmd, mock_tmpfile_copy):
+        ''' Testing when we fail to get objects '''
+
+        # Arrange
+
+        # run_ansible input parameters
+        params = {
+            'kubeconfig': '/etc/origin/master/admin.kubeconfig',
+        }
+
+        # Return values of our mocked function call. These get returned once per call.
+        mock_cmd.side_effect = [
+            # First call to mock
+            (1, '', 'Error.'),
+        ]
+
+        mock_tmpfile_copy.side_effect = [
+            '/tmp/mocked_kubeconfig',
+        ]
+
+        error_results = {
+            'returncode': 1,
+            'stderr': 'Error.',
+            'stdout': '',
+            'cmd': 'oc get hostsubnet -o json -n default',
+            'results': [{}]
+        }
+
+        # Act
+        results = OCObjectValidator.run_ansible(params)
+
+        # Assert
+        self.assertTrue(results['failed'])
+        self.assertEqual(results['msg'], 'Failed to GET hostsubnet.')
+        self.assertEqual(results['state'], 'list')
+        self.assertEqual(results['results'], error_results)
+
+        # Making sure our mock was called as we expected
+        mock_cmd.assert_has_calls([
+            mock.call(['oc', 'get', 'hostsubnet', '-o', 'json', '-n', 'default'], None),
+        ])
+
+    @mock.patch('oc_objectvalidator.Utils.create_tmpfile_copy')
+    @mock.patch('oc_objectvalidator.OCObjectValidator._run')
+    def test_valid_both(self, mock_cmd, mock_tmpfile_copy):
+        ''' Testing when both all objects are valid '''
+
+        # Arrange
+
+        # run_ansible input parameters
+        params = {
+            'kubeconfig': '/etc/origin/master/admin.kubeconfig',
+        }
+
+        valid_hostsubnet = '''{
+    "apiVersion": "v1",
+    "items": [
+        {
+            "apiVersion": "v1",
+            "host": "bar0",
+            "hostIP": "1.1.1.1",
+            "kind": "HostSubnet",
+            "metadata": {
+                "creationTimestamp": "2017-02-16T18:47:09Z",
+                "name": "bar0",
+                "namespace": "",
+                "resourceVersion": "986",
+                "selfLink": "/oapi/v1/hostsubnetsbar0",
+                "uid": "528dbb41-f478-11e6-aae0-507b9dac97ff"
+            },
+            "subnet": "1.1.0.0/24"
+        },
+        {
+            "apiVersion": "v1",
+            "host": "bar1",
+            "hostIP": "1.1.1.1",
+            "kind": "HostSubnet",
+            "metadata": {
+                "creationTimestamp": "2017-02-16T18:47:18Z",
+                "name": "bar1",
+                "namespace": "",
+                "resourceVersion": "988",
+                "selfLink": "/oapi/v1/hostsubnetsbar1",
+                "uid": "57710d84-f478-11e6-aae0-507b9dac97ff"
+            },
+            "subnet": "1.1.0.0/24"
+        },
+        {
+            "apiVersion": "v1",
+            "host": "bar2",
+            "hostIP": "1.1.1.1",
+            "kind": "HostSubnet",
+            "metadata": {
+                "creationTimestamp": "2017-02-16T18:47:26Z",
+                "name": "bar2",
+                "namespace": "",
+                "resourceVersion": "991",
+                "selfLink": "/oapi/v1/hostsubnetsbar2",
+                "uid": "5c59a28c-f478-11e6-aae0-507b9dac97ff"
+            },
+            "subnet": "1.1.0.0/24"
+        }
+    ],
+    "kind": "List",
+    "metadata": {},
+    "resourceVersion": "",
+    "selfLink": ""
+    }'''
+
+        valid_netnamespace = '''{
+    "apiVersion": "v1",
+    "items": [
+        {
+            "apiVersion": "v1",
+            "kind": "NetNamespace",
+            "metadata": {
+                "creationTimestamp": "2017-02-16T18:45:16Z",
+                "name": "foo0",
+                "namespace": "",
+                "resourceVersion": "959",
+                "selfLink": "/oapi/v1/netnamespacesfoo0",
+                "uid": "0f1c85b2-f478-11e6-aae0-507b9dac97ff"
+            },
+            "netid": 100,
+            "netname": "foo0"
+        },
+        {
+            "apiVersion": "v1",
+            "kind": "NetNamespace",
+            "metadata": {
+                "creationTimestamp": "2017-02-16T18:45:26Z",
+                "name": "foo1",
+                "namespace": "",
+                "resourceVersion": "962",
+                "selfLink": "/oapi/v1/netnamespacesfoo1",
+                "uid": "14effa0d-f478-11e6-aae0-507b9dac97ff"
+            },
+            "netid": 100,
+            "netname": "foo1"
+        },
+        {
+            "apiVersion": "v1",
+            "kind": "NetNamespace",
+            "metadata": {
+                "creationTimestamp": "2017-02-16T18:45:36Z",
+                "name": "foo2",
+                "namespace": "",
+                "resourceVersion": "965",
+                "selfLink": "/oapi/v1/netnamespacesfoo2",
+                "uid": "1aabdf84-f478-11e6-aae0-507b9dac97ff"
+            },
+            "netid": 100,
+            "netname": "foo2"
+        }
+    ],
+    "kind": "List",
+    "metadata": {},
+    "resourceVersion": "",
+    "selfLink": ""
+    }'''
+
+        valid_namespace = '''{
+    "apiVersion": "v1",
+    "items": [
+        {
+            "apiVersion": "v1",
+            "kind": "Namespace",
+            "metadata": {
+                "annotations": {
+                    "openshift.io/sa.scc.mcs": "s0:c1,c0",
+                    "openshift.io/sa.scc.supplemental-groups": "1000000000/10000",
+                    "openshift.io/sa.scc.uid-range": "1000000000/10000"
+                },
+                "creationTimestamp": "2017-03-02T00:49:49Z",
+                "name": "default",
+                "namespace": "",
+                "resourceVersion": "165",
+                "selfLink": "/api/v1/namespacesdefault",
+                "uid": "23c0c6aa-fee2-11e6-b45a-507b9dac97ff"
+            },
+            "spec": {
+                "finalizers": [
+                    "kubernetes",
+                    "openshift.io/origin"
+                ]
+            },
+            "status": {
+                "phase": "Active"
+            }
+        },
+        {
+            "apiVersion": "v1",
+            "kind": "Namespace",
+            "metadata": {
+                "annotations": {
+                    "openshift.io/sa.scc.mcs": "s0:c3,c2",
+                    "openshift.io/sa.scc.supplemental-groups": "1000010000/10000",
+                    "openshift.io/sa.scc.uid-range": "1000010000/10000"
+                },
+                "creationTimestamp": "2017-03-02T00:49:49Z",
+                "name": "kube-system",
+                "namespace": "",
+                "resourceVersion": "533",
+                "selfLink": "/api/v1/namespaceskube-system",
+                "uid": "23c21758-fee2-11e6-b45a-507b9dac97ff"
+            },
+            "spec": {
+                "finalizers": [
+                    "kubernetes",
+                    "openshift.io/origin"
+                ]
+            },
+            "status": {
+                "phase": "Active"
+            }
+        },
+        {
+            "apiVersion": "v1",
+            "kind": "Namespace",
+            "metadata": {
+                "annotations": {
+                    "openshift.io/description": "",
+                    "openshift.io/display-name": "",
+                    "openshift.io/requester": "developer",
+                    "openshift.io/sa.scc.mcs": "s0:c9,c4",
+                    "openshift.io/sa.scc.supplemental-groups": "1000080000/10000",
+                    "openshift.io/sa.scc.uid-range": "1000080000/10000"
+                },
+                "creationTimestamp": "2017-03-02T02:17:16Z",
+                "name": "myproject",
+                "namespace": "",
+                "resourceVersion": "2898",
+                "selfLink": "/api/v1/namespacesmyproject",
+                "uid": "5ae3764d-feee-11e6-b45a-507b9dac97ff"
+            },
+            "spec": {
+                "finalizers": [
+                    "openshift.io/origin",
+                    "kubernetes"
+                ]
+            },
+            "status": {
+                "phase": "Active"
+            }
+        },
+        {
+            "apiVersion": "v1",
+            "kind": "Namespace",
+            "metadata": {
+                "annotations": {
+                    "openshift.io/sa.scc.mcs": "s0:c6,c0",
+                    "openshift.io/sa.scc.supplemental-groups": "1000030000/10000",
+                    "openshift.io/sa.scc.uid-range": "1000030000/10000"
+                },
+                "creationTimestamp": "2017-03-02T00:49:51Z",
+                "name": "openshift",
+                "namespace": "",
+                "resourceVersion": "171",
+                "selfLink": "/api/v1/namespacesopenshift",
+                "uid": "24f7b34d-fee2-11e6-b45a-507b9dac97ff"
+            },
+            "spec": {
+                "finalizers": [
+                    "kubernetes",
+                    "openshift.io/origin"
+                ]
+            },
+            "status": {
+                "phase": "Active"
+            }
+        },
+        {
+            "apiVersion": "v1",
+            "kind": "Namespace",
+            "metadata": {
+                "annotations": {
+                    "openshift.io/sa.scc.mcs": "s0:c5,c0",
+                    "openshift.io/sa.scc.supplemental-groups": "1000020000/10000",
+                    "openshift.io/sa.scc.uid-range": "1000020000/10000"
+                },
+                "creationTimestamp": "2017-03-02T00:49:51Z",
+                "name": "openshift-infra",
+                "namespace": "",
+                "resourceVersion": "169",
+                "selfLink": "/api/v1/namespacesopenshift-infra",
+                "uid": "24a2ed75-fee2-11e6-b45a-507b9dac97ff"
+            },
+            "spec": {
+                "finalizers": [
+                    "kubernetes",
+                    "openshift.io/origin"
+                ]
+            },
+            "status": {
+                "phase": "Active"
+            }
+        },
+        {
+            "apiVersion": "v1",
+            "kind": "Namespace",
+            "metadata": {
+                "annotations": {
+                    "openshift.io/description": "",
+                    "openshift.io/display-name": "",
+                    "openshift.io/requester": "developer1",
+                    "openshift.io/sa.scc.mcs": "s0:c10,c0",
+                    "openshift.io/sa.scc.supplemental-groups": "1000090000/10000",
+                    "openshift.io/sa.scc.uid-range": "1000090000/10000"
+                },
+                "creationTimestamp": "2017-03-02T02:17:56Z",
+                "name": "yourproject",
+                "namespace": "",
+                "resourceVersion": "2955",
+                "selfLink": "/api/v1/namespacesyourproject",
+                "uid": "72df7fb9-feee-11e6-b45a-507b9dac97ff"
+            },
+            "spec": {
+                "finalizers": [
+                    "openshift.io/origin",
+                    "kubernetes"
+                ]
+            },
+            "status": {
+                "phase": "Active"
+            }
+        }
+    ],
+    "kind": "List",
+    "metadata": {},
+    "resourceVersion": "",
+    "selfLink": ""
+}'''
+
+        # Return values of our mocked function call. These get returned once per call.
+        mock_cmd.side_effect = [
+            # First call to mock
+            (0, valid_hostsubnet, ''),
+
+            # Second call to mock
+            (0, valid_netnamespace, ''),
+
+            # Third call to mock
+            (0, valid_namespace, ''),
+        ]
+
+        mock_tmpfile_copy.side_effect = [
+            '/tmp/mocked_kubeconfig',
+        ]
+
+        # Act
+        results = OCObjectValidator.run_ansible(params)
+
+        # Assert
+        self.assertNotIn('failed', results)
+        self.assertEqual(results['msg'], 'All objects are valid.')
+
+        # Making sure our mock was called as we expected
+        mock_cmd.assert_has_calls([
+            mock.call(['oc', 'get', 'hostsubnet', '-o', 'json', '-n', 'default'], None),
+            mock.call(['oc', 'get', 'netnamespace', '-o', 'json', '-n', 'default'], None),
+            mock.call(['oc', 'get', 'namespace', '-o', 'json', '-n', 'default'], None),
+        ])
+
+    @mock.patch('oc_objectvalidator.Utils.create_tmpfile_copy')
+    @mock.patch('oc_objectvalidator.OCObjectValidator._run')
+    def test_invalid_both(self, mock_cmd, mock_tmpfile_copy):
+        ''' Testing when all objects are invalid '''
+
+        # Arrange
+
+        # run_ansible input parameters
+        params = {
+            'kubeconfig': '/etc/origin/master/admin.kubeconfig',
+        }
+
+        invalid_hostsubnet = '''{
+    "apiVersion": "v1",
+    "items": [
+        {
+            "apiVersion": "v1",
+            "host": "bar0",
+            "hostIP": "1.1.1.1",
+            "kind": "HostSubnet",
+            "metadata": {
+                "creationTimestamp": "2017-02-16T18:47:09Z",
+                "name": "bar0",
+                "namespace": "",
+                "resourceVersion": "986",
+                "selfLink": "/oapi/v1/hostsubnetsbar0",
+                "uid": "528dbb41-f478-11e6-aae0-507b9dac97ff"
+            },
+            "subnet": "1.1.0.0/24"
+        },
+        {
+            "apiVersion": "v1",
+            "host": "bar1",
+            "hostIP": "1.1.1.1",
+            "kind": "HostSubnet",
+            "metadata": {
+                "creationTimestamp": "2017-02-16T18:47:18Z",
+                "name": "bar1",
+                "namespace": "",
+                "resourceVersion": "988",
+                "selfLink": "/oapi/v1/hostsubnetsbar1",
+                "uid": "57710d84-f478-11e6-aae0-507b9dac97ff"
+            },
+            "subnet": "1.1.0.0/24"
+        },
+        {
+            "apiVersion": "v1",
+            "host": "bar2",
+            "hostIP": "1.1.1.1",
+            "kind": "HostSubnet",
+            "metadata": {
+                "creationTimestamp": "2017-02-16T18:47:26Z",
+                "name": "bar2",
+                "namespace": "",
+                "resourceVersion": "991",
+                "selfLink": "/oapi/v1/hostsubnetsbar2",
+                "uid": "5c59a28c-f478-11e6-aae0-507b9dac97ff"
+            },
+            "subnet": "1.1.0.0/24"
+        },
+        {
+            "apiVersion": "v1",
+            "host": "baz1",
+            "hostIP": "1.1.1.1",
+            "kind": "HostSubnet",
+            "metadata": {
+                "creationTimestamp": "2017-02-16T18:47:49Z",
+                "name": "baz0",
+                "namespace": "",
+                "resourceVersion": "996",
+                "selfLink": "/oapi/v1/hostsubnetsbaz0",
+                "uid": "69f75f87-f478-11e6-aae0-507b9dac97ff"
+            },
+            "subnet": "1.1.0.0/24"
+        }
+    ],
+    "kind": "List",
+    "metadata": {},
+    "resourceVersion": "",
+    "selfLink": ""
+}'''
+
+        invalid_netnamespace = '''{
+    "apiVersion": "v1",
+    "items": [
+        {
+            "apiVersion": "v1",
+            "kind": "NetNamespace",
+            "metadata": {
+                "creationTimestamp": "2017-02-16T18:45:52Z",
+                "name": "bar0",
+                "namespace": "",
+                "resourceVersion": "969",
+                "selfLink": "/oapi/v1/netnamespacesbar0",
+                "uid": "245d416e-f478-11e6-aae0-507b9dac97ff"
+            },
+            "netid": 100,
+            "netname": "bar1"
+        },
+        {
+            "apiVersion": "v1",
+            "kind": "NetNamespace",
+            "metadata": {
+                "creationTimestamp": "2017-02-16T18:45:16Z",
+                "name": "foo0",
+                "namespace": "",
+                "resourceVersion": "959",
+                "selfLink": "/oapi/v1/netnamespacesfoo0",
+                "uid": "0f1c85b2-f478-11e6-aae0-507b9dac97ff"
+            },
+            "netid": 100,
+            "netname": "foo0"
+        },
+        {
+            "apiVersion": "v1",
+            "kind": "NetNamespace",
+            "metadata": {
+                "creationTimestamp": "2017-02-16T18:45:26Z",
+                "name": "foo1",
+                "namespace": "",
+                "resourceVersion": "962",
+                "selfLink": "/oapi/v1/netnamespacesfoo1",
+                "uid": "14effa0d-f478-11e6-aae0-507b9dac97ff"
+            },
+            "netid": 100,
+            "netname": "foo1"
+        },
+        {
+            "apiVersion": "v1",
+            "kind": "NetNamespace",
+            "metadata": {
+                "creationTimestamp": "2017-02-16T18:45:36Z",
+                "name": "foo2",
+                "namespace": "",
+                "resourceVersion": "965",
+                "selfLink": "/oapi/v1/netnamespacesfoo2",
+                "uid": "1aabdf84-f478-11e6-aae0-507b9dac97ff"
+            },
+            "netid": 100,
+            "netname": "foo2"
+        }
+    ],
+    "kind": "List",
+    "metadata": {},
+    "resourceVersion": "",
+    "selfLink": ""
+}'''
+
+        invalid_namespace = '''{
+    "apiVersion": "v1",
+    "items": [
+        {
+            "apiVersion": "v1",
+            "kind": "Namespace",
+            "metadata": {
+                "annotations": {
+                    "openshift.io/sa.scc.mcs": "s0:c1,c0",
+                    "openshift.io/sa.scc.supplemental-groups": "1000000000/10000",
+                    "openshift.io/sa.scc.uid-range": "1000000000/10000"
+                },
+                "creationTimestamp": "2017-03-02T00:49:49Z",
+                "name": "default",
+                "namespace": "",
+                "resourceVersion": "165",
+                "selfLink": "/api/v1/namespacesdefault",
+                "uid": "23c0c6aa-fee2-11e6-b45a-507b9dac97ff"
+            },
+            "spec": {
+                "finalizers": [
+                    "kubernetes",
+                    "openshift.io/origin"
+                ]
+            },
+            "status": {
+                "phase": "Active"
+            }
+        },
+        {
+            "apiVersion": "v1",
+            "kind": "Namespace",
+            "metadata": {
+                "annotations": {
+                    "openshift.io/requester": "",
+                    "openshift.io/sa.scc.mcs": "s0:c3,c2",
+                    "openshift.io/sa.scc.supplemental-groups": "1000010000/10000",
+                    "openshift.io/sa.scc.uid-range": "1000010000/10000"
+                },
+                "creationTimestamp": "2017-03-02T00:49:49Z",
+                "name": "kube-system",
+                "namespace": "",
+                "resourceVersion": "3052",
+                "selfLink": "/api/v1/namespaceskube-system",
+                "uid": "23c21758-fee2-11e6-b45a-507b9dac97ff"
+            },
+            "spec": {
+                "finalizers": [
+                    "kubernetes",
+                    "openshift.io/origin"
+                ]
+            },
+            "status": {
+                "phase": "Active"
+            }
+        },
+        {
+            "apiVersion": "v1",
+            "kind": "Namespace",
+            "metadata": {
+                "annotations": {
+                    "openshift.io/description": "",
+                    "openshift.io/display-name": "",
+                    "openshift.io/requester": "developer",
+                    "openshift.io/sa.scc.mcs": "s0:c9,c4",
+                    "openshift.io/sa.scc.supplemental-groups": "1000080000/10000",
+                    "openshift.io/sa.scc.uid-range": "1000080000/10000"
+                },
+                "creationTimestamp": "2017-03-02T02:17:16Z",
+                "name": "myproject",
+                "namespace": "",
+                "resourceVersion": "2898",
+                "selfLink": "/api/v1/namespacesmyproject",
+                "uid": "5ae3764d-feee-11e6-b45a-507b9dac97ff"
+            },
+            "spec": {
+                "finalizers": [
+                    "openshift.io/origin",
+                    "kubernetes"
+                ]
+            },
+            "status": {
+                "phase": "Active"
+            }
+        },
+        {
+            "apiVersion": "v1",
+            "kind": "Namespace",
+            "metadata": {
+                "annotations": {
+                    "openshift.io/requester": "",
+                    "openshift.io/sa.scc.mcs": "s0:c6,c0",
+                    "openshift.io/sa.scc.supplemental-groups": "1000030000/10000",
+                    "openshift.io/sa.scc.uid-range": "1000030000/10000"
+                },
+                "creationTimestamp": "2017-03-02T00:49:51Z",
+                "name": "openshift",
+                "namespace": "",
+                "resourceVersion": "3057",
+                "selfLink": "/api/v1/namespacesopenshift",
+                "uid": "24f7b34d-fee2-11e6-b45a-507b9dac97ff"
+            },
+            "spec": {
+                "finalizers": [
+                    "kubernetes",
+                    "openshift.io/origin"
+                ]
+            },
+            "status": {
+                "phase": "Active"
+            }
+        },
+        {
+            "apiVersion": "v1",
+            "kind": "Namespace",
+            "metadata": {
+                "annotations": {
+                    "openshift.io/description": "",
+                    "openshift.io/display-name": "",
+                    "openshift.io/requester": "system:admin",
+                    "openshift.io/sa.scc.mcs": "s0:c10,c5",
+                    "openshift.io/sa.scc.supplemental-groups": "1000100000/10000",
+                    "openshift.io/sa.scc.uid-range": "1000100000/10000"
+                },
+                "creationTimestamp": "2017-03-02T02:21:15Z",
+                "name": "openshift-fancy",
+                "namespace": "",
+                "resourceVersion": "3072",
+                "selfLink": "/api/v1/namespacesopenshift-fancy",
+                "uid": "e958063c-feee-11e6-b45a-507b9dac97ff"
+            },
+            "spec": {
+                "finalizers": [
+                    "openshift.io/origin",
+                    "kubernetes"
+                ]
+            },
+            "status": {
+                "phase": "Active"
+            }
+        },
+        {
+            "apiVersion": "v1",
+            "kind": "Namespace",
+            "metadata": {
+                "annotations": {
+                    "openshift.io/sa.scc.mcs": "s0:c5,c0",
+                    "openshift.io/sa.scc.supplemental-groups": "1000020000/10000",
+                    "openshift.io/sa.scc.uid-range": "1000020000/10000"
+                },
+                "creationTimestamp": "2017-03-02T00:49:51Z",
+                "name": "openshift-infra",
+                "namespace": "",
+                "resourceVersion": "169",
+                "selfLink": "/api/v1/namespacesopenshift-infra",
+                "uid": "24a2ed75-fee2-11e6-b45a-507b9dac97ff"
+            },
+            "spec": {
+                "finalizers": [
+                    "kubernetes",
+                    "openshift.io/origin"
+                ]
+            },
+            "status": {
+                "phase": "Active"
+            }
+        },
+        {
+            "apiVersion": "v1",
+            "kind": "Namespace",
+            "metadata": {
+                "annotations": {
+                    "openshift.io/description": "",
+                    "openshift.io/display-name": "",
+                    "openshift.io/requester": "developer1",
+                    "openshift.io/sa.scc.mcs": "s0:c10,c0",
+                    "openshift.io/sa.scc.supplemental-groups": "1000090000/10000",
+                    "openshift.io/sa.scc.uid-range": "1000090000/10000"
+                },
+                "creationTimestamp": "2017-03-02T02:17:56Z",
+                "name": "yourproject",
+                "namespace": "",
+                "resourceVersion": "2955",
+                "selfLink": "/api/v1/namespacesyourproject",
+                "uid": "72df7fb9-feee-11e6-b45a-507b9dac97ff"
+            },
+            "spec": {
+                "finalizers": [
+                    "openshift.io/origin",
+                    "kubernetes"
+                ]
+            },
+            "status": {
+                "phase": "Active"
+            }
+        }
+    ],
+    "kind": "List",
+    "metadata": {},
+    "resourceVersion": "",
+    "selfLink": ""
+}'''
+
+        invalid_results = {
+            'hostsubnets where metadata.name != host': [{
+                'apiVersion': 'v1',
+                'host': 'baz1',
+                'hostIP': '1.1.1.1',
+                'kind': 'HostSubnet',
+                'metadata': {
+                    'creationTimestamp': '2017-02-16T18:47:49Z',
+                    'name': 'baz0',
+                    'namespace': '',
+                    'resourceVersion': '996',
+                    'selfLink': '/oapi/v1/hostsubnetsbaz0',
+                    'uid': '69f75f87-f478-11e6-aae0-507b9dac97ff'
+                },
+                'subnet': '1.1.0.0/24'
+            }],
+            'netnamespaces where metadata.name != netname': [{
+                'apiVersion': 'v1',
+                'kind': 'NetNamespace',
+                'metadata': {
+                    'creationTimestamp': '2017-02-16T18:45:52Z',
+                    'name': 'bar0',
+                    'namespace': '',
+                    'resourceVersion': '969',
+                    'selfLink': '/oapi/v1/netnamespacesbar0',
+                    'uid': '245d416e-f478-11e6-aae0-507b9dac97ff'
+                },
+                'netid': 100,
+                'netname': 'bar1'
+            }],
+            'namespaces that use reserved names and were not created by infrastructure components': [{
+                'apiVersion': 'v1',
+                'kind': 'Namespace',
+                'metadata': {'annotations': {'openshift.io/requester': '',
+                                             'openshift.io/sa.scc.mcs': 's0:c3,c2',
+                                             'openshift.io/sa.scc.supplemental-groups': '1000010000/10000',
+                                             'openshift.io/sa.scc.uid-range': '1000010000/10000'},
+                             'creationTimestamp': '2017-03-02T00:49:49Z',
+                             'name': 'kube-system',
+                             'namespace': '',
+                             'resourceVersion': '3052',
+                             'selfLink': '/api/v1/namespaceskube-system',
+                             'uid': '23c21758-fee2-11e6-b45a-507b9dac97ff'},
+                'spec': {'finalizers': ['kubernetes', 'openshift.io/origin']},
+                'status': {'phase': 'Active'}},
+                {'apiVersion': 'v1',
+                 'kind': 'Namespace',
+                 'metadata': {'annotations': {'openshift.io/requester': '',
+                                              'openshift.io/sa.scc.mcs': 's0:c6,c0',
+                                              'openshift.io/sa.scc.supplemental-groups': '1000030000/10000',
+                                              'openshift.io/sa.scc.uid-range': '1000030000/10000'},
+                              'creationTimestamp': '2017-03-02T00:49:51Z',
+                              'name': 'openshift',
+                              'namespace': '',
+                              'resourceVersion': '3057',
+                              'selfLink': '/api/v1/namespacesopenshift',
+                              'uid': '24f7b34d-fee2-11e6-b45a-507b9dac97ff'},
+                 'spec': {'finalizers': ['kubernetes', 'openshift.io/origin']},
+                 'status': {'phase': 'Active'}},
+                {'apiVersion': 'v1',
+                 'kind': 'Namespace',
+                 'metadata': {'annotations': {'openshift.io/description': '',
+                                              'openshift.io/display-name': '',
+                                              'openshift.io/requester': 'system:admin',
+                                              'openshift.io/sa.scc.mcs': 's0:c10,c5',
+                                              'openshift.io/sa.scc.supplemental-groups': '1000100000/10000',
+                                              'openshift.io/sa.scc.uid-range': '1000100000/10000'},
+                              'creationTimestamp': '2017-03-02T02:21:15Z',
+                              'name': 'openshift-fancy',
+                              'namespace': '',
+                              'resourceVersion': '3072',
+                              'selfLink': '/api/v1/namespacesopenshift-fancy',
+                              'uid': 'e958063c-feee-11e6-b45a-507b9dac97ff'},
+                 'spec': {'finalizers': ['openshift.io/origin', 'kubernetes']},
+                 'status': {'phase': 'Active'}
+                 }],
+        }
+
+        # Return values of our mocked function call. These get returned once per call.
+        mock_cmd.side_effect = [
+            # First call to mock
+            (0, invalid_hostsubnet, ''),
+
+            # Second call to mock
+            (0, invalid_netnamespace, ''),
+
+            # Third call to mock
+            (0, invalid_namespace, ''),
+        ]
+
+        mock_tmpfile_copy.side_effect = [
+            '/tmp/mocked_kubeconfig',
+        ]
+
+        # Act
+        results = OCObjectValidator.run_ansible(params)
+
+        # Assert
+        self.assertTrue(results['failed'])
+        self.assertEqual(results['msg'], 'All objects are not valid.')
+        self.assertEqual(results['state'], 'list')
+        self.assertEqual(results['results'], invalid_results)
+
+        # Making sure our mock was called as we expected
+        mock_cmd.assert_has_calls([
+            mock.call(['oc', 'get', 'hostsubnet', '-o', 'json', '-n', 'default'], None),
+            mock.call(['oc', 'get', 'netnamespace', '-o', 'json', '-n', 'default'], None),
+            mock.call(['oc', 'get', 'namespace', '-o', 'json', '-n', 'default'], None),
+        ])
+
+
+if __name__ == '__main__':
+    unittest.main()