示例#1
0
 def test_deployment_check_connect_failed(self, mock_clients_services):
     sample_credential = objects.Credential("http://192.168.1.1:5000/v2.0/",
                                            "admin", "adminpass").to_dict()
     deployment = {"admin": sample_credential}
     refused = keystone_exceptions.ConnectionRefused()
     mock_clients_services.side_effect = refused
     self.assertRaises(keystone_exceptions.ConnectionRefused,
                       api.Deployment.check, deployment)
示例#2
0
 def test_deployment_check_connect_failed(self, mock_deployment_get,
                                          mock_clients_services):
     deployment_id = "e87e4dca-b515-4477-888d-5f6103f13b42"
     sample_endpoint = objects.Endpoint("http://192.168.1.1:5000/v2.0/",
                                        "admin", "adminpass").to_dict()
     mock_deployment_get.return_value = {"admin": sample_endpoint}
     refused = keystone_exceptions.ConnectionRefused()
     mock_clients_services.side_effect = refused
     self.assertEqual(self.deployment.check(deployment_id), 1)
示例#3
0
 def test_deployment_check_raise(self, mock_deployment_get,
                                 mock_deployment_check):
     deployment_id = "e87e4dca-b515-4477-888d-5f6103f13b42"
     sample_credential = objects.Credential("http://192.168.1.1:5000/v2.0/",
                                            "admin", "adminpass").to_dict()
     sample_credential["not-exist-key"] = "error"
     mock_deployment_get.return_value = {"admin": sample_credential}
     refused = keystone_exceptions.ConnectionRefused()
     mock_deployment_check.side_effect = refused
     self.assertEqual(self.deployment.check(deployment_id), 1)
示例#4
0
        def a(a):
            if a == 1:
                raise keystone_exc.Unauthorized()

            if a == 2:
                raise keystone_exc.AuthorizationFailure()

            if a == 3:
                raise keystone_exc.ConnectionRefused()

            return a
示例#5
0
    def _send_request(self, url, method, redirect, **kwargs):
        # NOTE(jamielennox): We handle redirection manually because the
        # requests lib follows some browser patterns where it will redirect
        # POSTs as GETs for certain statuses which is not want we want for an
        # API. See: https://en.wikipedia.org/wiki/Post/Redirect/Get

        try:
            resp = self.session.request(method, url, **kwargs)
        except requests.exceptions.SSLError:
            msg = 'SSL exception connecting to %s' % url
            raise exceptions.SSLError(msg)
        except requests.exceptions.Timeout:
            msg = 'Request to %s timed out' % url
            raise exceptions.RequestTimeout(msg)
        except requests.exceptions.ConnectionError:
            msg = 'Unable to establish connection to %s' % url
            raise exceptions.ConnectionRefused(msg)

        _logger.debug('RESP: [%s] %s\nRESP BODY: %s\n', resp.status_code,
                      resp.headers, resp.text)

        if resp.status_code in self.REDIRECT_STATUSES:
            # be careful here in python True == 1 and False == 0
            if isinstance(redirect, bool):
                redirect_allowed = redirect
            else:
                redirect -= 1
                redirect_allowed = redirect >= 0

            if not redirect_allowed:
                return resp

            try:
                location = resp.headers['location']
            except KeyError:
                _logger.warn(
                    "Failed to redirect request to %s as new "
                    "location was not provided.", resp.url)
            else:
                new_resp = self._send_request(location, method, redirect,
                                              **kwargs)

                if not isinstance(new_resp.history, list):
                    new_resp.history = list(new_resp.history)
                new_resp.history.insert(0, resp)
                resp = new_resp

        return resp
示例#6
0
    def _send_request(self,
                      url,
                      method,
                      redirect,
                      log,
                      logger,
                      connect_retries,
                      connect_retry_delay=0.5,
                      **kwargs):
        # NOTE(jamielennox): We handle redirection manually because the
        # requests lib follows some browser patterns where it will redirect
        # POSTs as GETs for certain statuses which is not want we want for an
        # API. See: https://en.wikipedia.org/wiki/Post/Redirect/Get

        # NOTE(jamielennox): The interaction between retries and redirects are
        # handled naively. We will attempt only a maximum number of retries and
        # redirects rather than per request limits. Otherwise the extreme case
        # could be redirects * retries requests. This will be sufficient in
        # most cases and can be fixed properly if there's ever a need.

        try:
            try:
                resp = self.session.request(method, url, **kwargs)
            except requests.exceptions.SSLError as e:
                msg = _('SSL exception connecting to %(url)s: '
                        '%(error)s') % {
                            'url': url,
                            'error': e
                        }
                raise exceptions.SSLError(msg)
            except requests.exceptions.Timeout:
                msg = _('Request to %s timed out') % url
                raise exceptions.RequestTimeout(msg)
            except requests.exceptions.ConnectionError:
                msg = _('Unable to establish connection to %s') % url
                raise exceptions.ConnectionRefused(msg)
        except (exceptions.RequestTimeout, exceptions.ConnectionRefused) as e:
            if connect_retries <= 0:
                raise

            logger.info(_LI('Failure: %(e)s. Retrying in %(delay).1fs.'), {
                'e': e,
                'delay': connect_retry_delay
            })
            time.sleep(connect_retry_delay)

            return self._send_request(url,
                                      method,
                                      redirect,
                                      log,
                                      logger,
                                      connect_retries=connect_retries - 1,
                                      connect_retry_delay=connect_retry_delay *
                                      2,
                                      **kwargs)

        if log:
            self._http_log_response(resp, logger)

        if resp.status_code in self._REDIRECT_STATUSES:
            # be careful here in python True == 1 and False == 0
            if isinstance(redirect, bool):
                redirect_allowed = redirect
            else:
                redirect -= 1
                redirect_allowed = redirect >= 0

            if not redirect_allowed:
                return resp

            try:
                location = resp.headers['location']
            except KeyError:
                logger.warning(
                    _LW("Failed to redirect request to %s as new "
                        "location was not provided."), resp.url)
            else:
                # NOTE(jamielennox): We don't pass through connect_retry_delay.
                # This request actually worked so we can reset the delay count.
                new_resp = self._send_request(location,
                                              method,
                                              redirect,
                                              log,
                                              logger,
                                              connect_retries=connect_retries,
                                              **kwargs)

                if not isinstance(new_resp.history, list):
                    new_resp.history = list(new_resp.history)
                new_resp.history.insert(0, resp)
                resp = new_resp

        return resp
示例#7
0
class ShellTest(utils.TestCase):

    FAKE_ENV = {
        'OS_USERNAME': '******',
        'OS_PASSWORD': '******',
        'OS_TENANT_NAME': 'tenant_name',
        'OS_AUTH_URL': 'http://no.where/v2.0',
    }

    # Patch os.environ to avoid required auth info.
    def make_env(self, exclude=None, include=None):
        env = dict((k, v) for k, v in self.FAKE_ENV.items() if k != exclude)
        env.update(include or {})
        self.useFixture(fixtures.MonkeyPatch('os.environ', env))

    def setUp(self):
        super(ShellTest, self).setUp()
        for var in self.FAKE_ENV:
            self.useFixture(
                fixtures.EnvironmentVariable(var, self.FAKE_ENV[var]))

    def shell(self, argstr):
        orig = sys.stdout
        try:
            sys.stdout = moves.StringIO()
            _shell = shell.OpenStackCinderShell()
            _shell.main(argstr.split())
        except SystemExit:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            self.assertEqual(0, exc_value.code)
        finally:
            out = sys.stdout.getvalue()
            sys.stdout.close()
            sys.stdout = orig

        return out

    def test_help_unknown_command(self):
        self.assertRaises(exceptions.CommandError, self.shell, 'help foofoo')

    def test_help(self):
        required = [
            '.*?^usage: ',
            '.*?(?m)^\s+create\s+Creates a volume.',
            '.*?(?m)^Run "cinder help SUBCOMMAND" for help on a subcommand.',
        ]
        help_text = self.shell('help')
        for r in required:
            self.assertThat(help_text,
                            matchers.MatchesRegex(r, re.DOTALL | re.MULTILINE))

    def test_help_on_subcommand(self):
        required = [
            '.*?^usage: cinder list',
            '.*?(?m)^Lists all volumes.',
        ]
        help_text = self.shell('help list')
        for r in required:
            self.assertThat(help_text,
                            matchers.MatchesRegex(r, re.DOTALL | re.MULTILINE))

    def register_keystone_auth_fixture(self, mocker, url):
        mocker.register_uri('GET',
                            url,
                            text=keystone_client.keystone_request_callback)

    @requests_mock.Mocker()
    def test_version_discovery(self, mocker):
        _shell = shell.OpenStackCinderShell()

        os_auth_url = "https://WrongDiscoveryResponse.discovery.com:35357/v2.0"
        self.register_keystone_auth_fixture(mocker, os_auth_url)
        self.assertRaises(DiscoveryFailure,
                          _shell._discover_auth_versions,
                          None,
                          auth_url=os_auth_url)

        os_auth_url = "https://DiscoveryNotSupported.discovery.com:35357/v2.0"
        self.register_keystone_auth_fixture(mocker, os_auth_url)
        v2_url, v3_url = _shell._discover_auth_versions(None,
                                                        auth_url=os_auth_url)
        self.assertEqual(v2_url, os_auth_url, "Expected v2 url")
        self.assertIsNone(v3_url, "Expected no v3 url")

        os_auth_url = "https://DiscoveryNotSupported.discovery.com:35357/v3.0"
        self.register_keystone_auth_fixture(mocker, os_auth_url)
        v2_url, v3_url = _shell._discover_auth_versions(None,
                                                        auth_url=os_auth_url)
        self.assertEqual(v3_url, os_auth_url, "Expected v3 url")
        self.assertIsNone(v2_url, "Expected no v2 url")

    @requests_mock.Mocker()
    def list_volumes_on_service(self, count, mocker):
        os_auth_url = "http://multiple.service.names/v2.0"
        mocker.register_uri('POST',
                            os_auth_url + "/tokens",
                            text=keystone_client.keystone_request_callback)
        mocker.register_uri('GET',
                            "http://cinder%i.api.com/v2/volumes/detail" %
                            count,
                            text='{"volumes": []}')
        self.make_env(include={
            'OS_AUTH_URL': os_auth_url,
            'CINDER_SERVICE_NAME': 'cinder%i' % count
        })
        _shell = shell.OpenStackCinderShell()
        _shell.main(['list'])

    def test_cinder_service_name(self):
        # Failing with 'No mock address' means we are not
        # choosing the correct endpoint
        for count in range(1, 4):
            self.list_volumes_on_service(count)

    @mock.patch('keystoneclient.adapter.Adapter.get_token',
                side_effect=ks_exc.ConnectionRefused())
    @mock.patch('keystoneclient.discover.Discover',
                side_effect=ks_exc.ConnectionRefused())
    @mock.patch('sys.stdin', side_effect=mock.MagicMock)
    @mock.patch('getpass.getpass', return_value='password')
    def test_password_prompted(self, mock_getpass, mock_stdin, mock_discover,
                               mock_token):
        self.make_env(exclude='OS_PASSWORD')
        _shell = shell.OpenStackCinderShell()
        self.assertRaises(ks_exc.ConnectionRefused, _shell.main, ['list'])
        mock_getpass.assert_called_with('OS Password: '******'fake' auth instead of keystone
        # and the auth plugin will provide the auth url
        self.make_env(exclude="OS_AUTH_URL",
                      include={'OS_AUTH_SYSTEM': 'fake'})
        # This should fail as we have not setup a mock response for 'list',
        # however auth should have been called
        _shell = shell.OpenStackCinderShell()
        self.assertRaises(KeyError, _shell.main, ['list'])

        headers = requested_headers(_shell.cs)
        token_url = _shell.cs.client.auth_url + "/tokens"
        self.assertEqual(non_keystone_auth_url + "/tokens", token_url)

        mock_request.assert_any_call("POST",
                                     token_url,
                                     headers=headers,
                                     data='{"fake": "me"}',
                                     allow_redirects=True,
                                     **self.TEST_REQUEST_BASE)

    @mock.patch.object(cinderclient.client.HTTPClient,
                       'authenticate',
                       side_effect=exceptions.Unauthorized('No'))
    # Easiest way to make cinderclient use httpclient is a None session
    @mock.patch.object(cinderclient.shell.OpenStackCinderShell,
                       '_get_keystone_session',
                       return_value=None)
    def test_http_client_insecure(self, mock_authenticate, mock_session):
        self.make_env(include={'CINDERCLIENT_INSECURE': True})

        _shell = shell.OpenStackCinderShell()

        # This "fails" but instantiates the client.
        self.assertRaises(exceptions.CommandError, _shell.main, ['list'])

        self.assertEqual(False, _shell.cs.client.verify_cert)