def test_make_update_body_static(self):
        """Ensure the update body generates correctly for a transition from dhcp to static"""
        iface = dict(
            id='1',
            ipv4Enabled=False,
            ipv4Data=dict(
                ipv4AddressConfigMethod='configDhcp',
                ipv4AddressData=dict(
                    ipv4Address="0.0.0.0",
                    ipv4SubnetMask="0.0.0.0",
                    ipv4GatewayAddress="0.0.0.0",
                ),
            ),
            interfaceData=dict(ethernetData=dict(
                maximumFramePayloadSize=1500, ), ),
        )

        self._set_args(
            dict(state='enabled',
                 config_method='static',
                 address='10.10.10.10',
                 subnet_mask='255.255.255.0',
                 gateway='1.1.1.1'))

        inst = IscsiInterface()
        update, body = inst.make_update_body(iface)
        self.assertTrue(update, msg="An update was expected!")
        self.assertEquals(body['settings']['ipv4Enabled'][0], True)
        self.assertEquals(body['settings']['ipv4AddressConfigMethod'][0],
                          'configStatic')
        self.assertEquals(body['settings']['ipv4Address'][0], '10.10.10.10')
        self.assertEquals(body['settings']['ipv4SubnetMask'][0],
                          '255.255.255.0')
        self.assertEquals(body['settings']['ipv4GatewayAddress'][0], '1.1.1.1')
    def test_update_not_required(self, get_controllers):
        """Ensure we don't trigger the update if one isn't required or if check mode is enabled"""
        self._set_args()

        # make_update_body will report that no change is required, so we should see no call to the API.
        inst = IscsiInterface()
        with self.assertRaises(AnsibleExitJson) as result:
            with mock.patch(self.REQ_FUNC, return_value=(200, "")) as request:
                with mock.patch.object(inst,
                                       'fetch_target_interface',
                                       side_effect=[{}, mock.MagicMock()]):
                    with mock.patch.object(inst,
                                           'make_update_body',
                                           return_value=(False, {})):
                        inst()
        request.assert_not_called()
        self.assertFalse(result.exception.args[0]['changed'],
                         msg="No change was expected.")

        # Since check_mode is enabled, we will run everything normally, but not make a request to the API
        #  to perform the actual change.
        inst = IscsiInterface()
        inst.check_mode = True
        with self.assertRaises(AnsibleExitJson) as result:
            with mock.patch(self.REQ_FUNC, return_value=(200, "")) as request:
                with mock.patch.object(inst,
                                       'fetch_target_interface',
                                       side_effect=[{}, mock.MagicMock()]):
                    with mock.patch.object(inst,
                                           'make_update_body',
                                           return_value=(True, {})):
                        inst()
        request.assert_not_called()
        self.assertTrue(result.exception.args[0]['changed'],
                        msg="A change was expected.")
    def test_fetch_target_interface_bad_channel(self):
        """Ensure we fail correctly when a bad channel is provided"""
        self._set_args()

        interfaces = list(dict(channel=1, controllerId='1'))

        with self.assertRaisesRegexp(AnsibleFailJson, r".*?channels include.*"):
            with mock.patch.object(IscsiInterface, 'interfaces', return_value=interfaces):
                iface = IscsiInterface()
                interfaces = iface.fetch_target_interface()
    def test_update_fail(self, get_controllers, make_body):
        """Ensure we fail correctly on receiving a normal failure from the API."""
        self._set_args()

        inst = IscsiInterface()
        # Test a 422 error with a non-busy status
        with self.assertRaisesRegexp(AnsibleFailJson, r".*?Failed to modify.*") as result:
            with mock.patch(self.REQ_FUNC, return_value=(422, mock.MagicMock())) as request:
                with mock.patch.object(inst, 'fetch_target_interface', side_effect=[{}, mock.MagicMock()]):
                    inst()
        request.assert_called_once()

        # Test a 401 (authentication) error
        with self.assertRaisesRegexp(AnsibleFailJson, r".*?Failed to modify.*") as result:
            with mock.patch(self.REQ_FUNC, return_value=(401, mock.MagicMock())) as request:
                with mock.patch.object(inst, 'fetch_target_interface', side_effect=[{}, mock.MagicMock()]):
                    inst()
        request.assert_called_once()

        # Test with a connection failure
        with self.assertRaisesRegexp(AnsibleFailJson, r".*?Connection failure.*") as result:
            with mock.patch(self.REQ_FUNC, side_effect=Exception()) as request:
                with mock.patch.object(inst, 'fetch_target_interface', side_effect=[{}, mock.MagicMock()]):
                    inst()
        request.assert_called_once()
    def test_update_bad_controller(self):
        """Ensure a bad controller fails gracefully"""
        self._set_args(dict(controller='B'))

        inst = IscsiInterface()
        with self.assertRaises(AnsibleFailJson) as result:
            with mock.patch.object(inst, 'get_controllers', return_value=dict(A='1')) as get_controllers:
                inst()
    def test_interfaces_fail(self):
        """Ensure we fail gracefully on an error to retrieve the interfaces"""
        self._set_args()

        with self.assertRaises(AnsibleFailJson) as result:
            # Simulate a failed call to the API
            with mock.patch(self.REQ_FUNC, side_effect=Exception("Failure")):
                iface = IscsiInterface()
                interfaces = iface.interfaces
    def test_update_fail_busy(self, get_controllers):
        """Ensure we fail correctly on receiving a busy response from the API."""
        self._set_args()

        inst = IscsiInterface()
        with self.assertRaisesRegexp(AnsibleFailJson, r".*?busy.*") as result:
            with mock.patch(self.REQ_FUNC, return_value=(422, dict(retcode="3"))) as request:
                with mock.patch.object(inst, 'fetch_target_interface', side_effect=[{}, mock.MagicMock()]):
                    with mock.patch.object(inst, 'make_update_body', return_value=(True, {})):
                        inst()
        request.assert_called_once()
    def test_update(self, get_controllers):
        """Validate the good path"""
        self._set_args()

        inst = IscsiInterface()
        with self.assertRaises(AnsibleExitJson):
            with mock.patch(self.REQ_FUNC, return_value=(200, "")) as request:
                with mock.patch.object(inst, 'fetch_target_interface', side_effect=[{}, mock.MagicMock()]):
                    with mock.patch.object(inst, 'make_update_body', return_value=(True, {})):
                        inst()
        request.assert_called_once()
    def test_invalid_params(self):
        """Ensure that our input validation catches invalid parameters"""

        # Currently a 'C' controller is invalid
        self._set_args(dict(
            state='disabled',
            name=1,
            controller="C",
        ))
        with self.assertRaises(AnsibleFailJson) as result:
            iface = IscsiInterface()

        # Each of these mtu values are invalid
        for mtu in [500, 1499, 9001]:
            self._set_args({
                'state': 'disabled',
                'name': 1,
                'controller': 'A',
                'mtu': mtu
            })
        with self.assertRaises(AnsibleFailJson) as result:
            iface = IscsiInterface()
 def test_validate_params(self):
     """Ensure we can pass valid parameters to the module"""
     # Provide a range of valid values for each
     for controller in ['A', 'B']:
         for i in range(1, 10):
             for mtu in [1500, 2500, 9000]:
                 self._set_args(dict(
                     state='disabled',
                     name=i,
                     controller=controller,
                     mtu=mtu,
                 ))
         iface = IscsiInterface()
    def test_interfaces(self):
        """Validate that we are processing the interface list properly"""
        self._set_args()

        interfaces = [
            dict(interfaceType='iscsi',
                 iscsi=dict()),
            dict(interfaceType='iscsi',
                 iscsi=dict()),
            dict(interfaceType='fc', )
        ]

        # Ensure we filter out anything without an interfaceType of iscsi
        expected = [iface['iscsi'] for iface in interfaces if iface['interfaceType'] == 'iscsi']

        # We expect a single call to the API: retrieve the list of interfaces from the objectGraph.
        with mock.patch(self.REQ_FUNC, return_value=(200, interfaces)):
            iface = IscsiInterface()
            interfaces = iface.interfaces
            self.assertEquals(interfaces, expected)