diff options
| -rw-r--r-- | roles/lib_openshift/library/oc_objectvalidator.py (renamed from roles/lib_openshift/library/oc_sdnvalidator.py) | 71 | ||||
| -rw-r--r-- | roles/lib_openshift/src/ansible/oc_objectvalidator.py (renamed from roles/lib_openshift/src/ansible/oc_sdnvalidator.py) | 4 | ||||
| -rw-r--r-- | roles/lib_openshift/src/class/oc_objectvalidator.py | 77 | ||||
| -rw-r--r-- | roles/lib_openshift/src/class/oc_sdnvalidator.py | 58 | ||||
| -rw-r--r-- | roles/lib_openshift/src/doc/objectvalidator (renamed from roles/lib_openshift/src/doc/sdnvalidator) | 14 | ||||
| -rw-r--r-- | roles/lib_openshift/src/sources.yml | 8 | ||||
| -rwxr-xr-x | roles/lib_openshift/src/test/unit/oc_sdnvalidator.py | 481 | ||||
| -rwxr-xr-x | roles/lib_openshift/src/test/unit/test_oc_objectvalidator.py | 916 | 
8 files changed, 1051 insertions, 578 deletions
diff --git a/roles/lib_openshift/library/oc_sdnvalidator.py b/roles/lib_openshift/library/oc_objectvalidator.py index bc7487b95..f6802a9b3 100644 --- a/roles/lib_openshift/library/oc_sdnvalidator.py +++ b/roles/lib_openshift/library/oc_objectvalidator.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 -*- -*- -*- diff --git a/roles/lib_openshift/src/ansible/oc_sdnvalidator.py b/roles/lib_openshift/src/ansible/oc_objectvalidator.py index e91417d63..658bb5ded 100644 --- a/roles/lib_openshift/src/ansible/oc_sdnvalidator.py +++ b/roles/lib_openshift/src/ansible/oc_objectvalidator.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) diff --git a/roles/lib_openshift/src/class/oc_objectvalidator.py b/roles/lib_openshift/src/class/oc_objectvalidator.py new file mode 100644 index 000000000..b76fc995e --- /dev/null +++ b/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.'} diff --git a/roles/lib_openshift/src/class/oc_sdnvalidator.py b/roles/lib_openshift/src/class/oc_sdnvalidator.py deleted file mode 100644 index da923337b..000000000 --- a/roles/lib_openshift/src/class/oc_sdnvalidator.py +++ /dev/null @@ -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.'} diff --git a/roles/lib_openshift/src/doc/sdnvalidator b/roles/lib_openshift/src/doc/objectvalidator index 0b1862ed1..98861e261 100644 --- a/roles/lib_openshift/src/doc/sdnvalidator +++ b/roles/lib_openshift/src/doc/objectvalidator @@ -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  ''' diff --git a/roles/lib_openshift/src/sources.yml b/roles/lib_openshift/src/sources.yml index c72fd4ea8..f16b3c8de 100644 --- a/roles/lib_openshift/src/sources.yml +++ b/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 diff --git a/roles/lib_openshift/src/test/unit/oc_sdnvalidator.py b/roles/lib_openshift/src/test/unit/oc_sdnvalidator.py deleted file mode 100755 index 49e2aadb2..000000000 --- a/roles/lib_openshift/src/test/unit/oc_sdnvalidator.py +++ /dev/null @@ -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() diff --git a/roles/lib_openshift/src/test/unit/test_oc_objectvalidator.py b/roles/lib_openshift/src/test/unit/test_oc_objectvalidator.py new file mode 100755 index 000000000..8235c71b8 --- /dev/null +++ b/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()  | 
