Exemple #1
0
    def request(self, method, url, **kwargs):
        """Send an HTTP request.

        Arguments passed directly in to this method override (but do not
        overwrite!) arguments specified in ``self.request_kwargs``.
        """
        # The `self.request_kwargs` dict should *always* have a "url" argument.
        # This is enforced by `self.__init__`. This allows us to call the
        # `requests.request` function and satisfy its signature:
        #
        #     request(method, url, **kwargs)
        #
        request_kwargs = self.request_kwargs.copy()
        request_kwargs['url'] = urljoin(request_kwargs['url'], url)
        request_kwargs.update(kwargs)
        config_host = urlparse(self._cfg.base_url).netloc
        request_host = urlparse(request_kwargs['url']).netloc
        if request_host != config_host:
            warnings.warn(
                'This client is configured to make HTTP requests to {0}, but '
                'a request is being made to {1}. The request will be made, '
                'but some options may be incorrect. For example, an incorrect '
                'SSL certificate may be specified with the `verify` option. '
                'Request options: {2}'
                .format(config_host, request_host, request_kwargs),
                RuntimeWarning
            )
        return self.response_handler(
            self._cfg,
            requests.request(method, **request_kwargs),
        )
Exemple #2
0
def _get_hostname(urlstring):
    """Get the hostname from a URL string.

    ``urlparse`` follows RFC 1808 and requires that network locations be
    prefixed with "//". This function is a thin wrapper. It treats the leading
    "//" as optional::

    >>> urls = ('ftp://localhost', '//localhost', 'localhost', 'localhost:123')
    >>> for url in urls:
    ...     print((_get_hostname(url), urlparse(url).hostname))
    ('localhost', 'localhost')
    ('localhost', 'localhost')
    ('localhost', None)
    ('localhost', None)

    Usage::

        if server_config is None:
            server_config = get_config()
        hostname = _get_hostname(server_config.base_url)

    :param urlstring: A string such as "localhost:3000", "pulp.example.com" or
        "https://pulp.example.com".
    :returns: A hostname, such as "localhost" or "pulp.example.com".

    """
    parts = urlparse(urlstring)
    if parts.hostname is None:
        return _get_hostname('//' + parts.path)
    else:
        return parts.hostname
Exemple #3
0
    def test_publish_to_web(self):
        """Publish the repository to the web, and fetch the ISO file.

        The ISO file should be available over both HTTP and HTTPS. Fetch it
        from both locations, and assert that the fetch was successful.
        """
        # Publish the repository, and re-read the distributor.
        client = api.Client(self.cfg, api.json_handler)
        path = urljoin(self.repo['_href'], 'actions/publish/')
        client.post(path, {'id': self.distributor['id']})
        distributor = client.get(self.distributor['_href'])

        # Build the path to the ISO file. By default, the file is named like
        # so: {repo_id}-{iso_creation_time}-{iso_number}.iso
        iso_creation_time = parse(
            distributor['last_publish']
        ).strftime('%Y-%m-%dT%H.%M')
        iso_name = '{}-{}-01.iso'.format(self.repo['id'], iso_creation_time)
        path = '/pulp/exports/repos/'
        path = urljoin(path, distributor['config']['relative_url'])
        iso_path = urljoin(path, iso_name)

        # Fetch the ISO file via HTTP and HTTPS.
        client.response_handler = api.safe_handler
        url = urljoin(self.cfg.base_url, iso_path)
        for scheme in ('http', 'https'):
            url = urlunparse((scheme,) + urlparse(url)[1:])
            with self.subTest(url=url):
                self.assertEqual(client.get(url).status_code, 200)
Exemple #4
0
def _get_hostname(urlstring):
    """Get the hostname from a URL string.

    ``urlparse`` follows RFC 1808 and requires that network locations be
    prefixed with "//". This function is a thin wrapper. It treats the leading
    "//" as optional::

    >>> urls = ('ftp://localhost', '//localhost', 'localhost', 'localhost:123')
    >>> for url in urls:
    ...     print((_get_hostname(url), urlparse(url).hostname))
    ('localhost', 'localhost')
    ('localhost', 'localhost')
    ('localhost', None)
    ('localhost', None)

    Usage::

        if server_config is None:
            server_config = get_config()
        hostname = _get_hostname(server_config.base_url)

    :param urlstring: A string such as "localhost:3000", "pulp.example.com" or
        "https://pulp.example.com".
    :returns: A hostname, such as "localhost" or "pulp.example.com".

    """
    parts = urlparse(urlstring)
    if parts.hostname is None:
        return _get_hostname('//' + parts.path)
    else:
        return parts.hostname
    def test_headers_location(self):
        # pylint:disable=line-too-long
        """Assert the response's ``Location`` header is correct.

        The ``Location`` may be either an absolute or relative URL. See
        :meth:`pulp_smash.tests.platform.api_v2.test_repository.CreateSuccessTestCase.test_location_header`.
        """
        actual_path = urlparse(self.response.headers['Location']).path
        expect_path = urljoin(REPOSITORY_PATH, self.body['id'] + '/')
        self.assertEqual(actual_path, expect_path)
    def test_all(self):
        """Publish a repository several times with the rsync distributor."""
        # Create a user and a repository. Sync the repo.
        ssh_user, priv_key = self.make_user(self.cfg)
        ssh_identity_file = self.write_private_key(self.cfg, priv_key)
        repo_href = self.make_repo(self.cfg, {
            'host': urlparse(self.cfg.base_url).netloc,
            'root': '/home/' + ssh_user,
            'ssh_identity_file': ssh_identity_file,
            'ssh_user': ssh_user,
        })
        utils.sync_repo(self.cfg, repo_href)

        # Publish with the yum and rsync distributors.
        api_client = api.Client(self.cfg)
        dists_by_type_id = _get_dists_by_type_id(self.cfg, repo_href)
        for type_id in ('yum_distributor', 'rpm_rsync_distributor'):
            body = {'id': dists_by_type_id[type_id]['id']}
            api_client.post(urljoin(repo_href, 'actions/publish/'), body)

        # Verify what the rsync distributor has done
        cli_client = cli.Client(self.cfg)
        sudo = '' if utils.is_root(self.cfg) else 'sudo '

        cmd = sudo + 'ls -1 /home/{}'.format(ssh_user)
        dirs = set(cli_client.run(cmd.split()).stdout.strip().split('\n'))
        self.assertGreaterEqual(dirs, {'content'})

        cmd = sudo + 'ls -1 /home/{}/content'.format(ssh_user)
        dirs = set(cli_client.run(cmd.split()).stdout.strip().split('\n'))
        self.assertGreaterEqual(dirs, {'units'})

        cmd = sudo + 'ls -1 /home/{}/content/units'.format(ssh_user)
        dirs = set(cli_client.run(cmd.split()).stdout.strip().split('\n'))
        self.assertGreaterEqual(dirs, {'rpm'})

        cmd = (sudo + (
            'find /home/{}/content/units/rpm/ -name *.rpm'.format(ssh_user)
        ))
        files = cli_client.run(cmd.split()).stdout.strip().split('\n')
        self.assertEqual(len(files), 32, files)
    def test_location_header(self):
        """Assert the Location header is correctly set in each response.

        According to RFC 7231, the `HTTP Location`_ header may be either an
        absolute or relative URL. Thus, given this request:

        .. code-block:: http

            GET /index.html HTTP/1.1
            Host: www.example.com

        These two responses are equivalent:

        .. code-block:: http

            HTTP/1.1 302 FOUND
            Location: http://www.example.com/index.php

        .. code-block:: http

            HTTP/1.1 302 FOUND
            Location: /index.php

        This test abides by the RFC and allows Pulp to return either absolute
        or relative URLs.

        .. _HTTP Location: https://en.wikipedia.org/wiki/HTTP_location
        """
        for body, response in zip(self.bodies, self.responses):
            with self.subTest(body=body):
                # >>> urlparse('http://example.com/index.php').path == \
                # ... urlparse('/index.php').path
                # True
                actual_path = urlparse(response.headers['Location']).path
                expect_path = urljoin(REPOSITORY_PATH, body['id'] + '/')
                self.assertEqual(actual_path, expect_path)
    def test_all(self):
        """Publish the rpm rsync distributor before the yum distributor."""
        # Create a user and a repository.
        ssh_user, priv_key = self.make_user(self.cfg)
        ssh_identity_file = self.write_private_key(self.cfg, priv_key)
        repo_href = self.make_repo(self.cfg, {
            'host': urlparse(self.cfg.base_url).netloc,
            'root': '/home/' + ssh_user,
            'ssh_identity_file': ssh_identity_file,
            'ssh_user': ssh_user,
        })

        # Publish with the rsync distributor.
        dists_by_type_id = _get_dists_by_type_id(self.cfg, repo_href)
        with self.assertRaises(exceptions.TaskReportError):
            api.Client(self.cfg).post(urljoin(repo_href, 'actions/publish/'), {
                'id': dists_by_type_id['rpm_rsync_distributor']['id'],
            })

        # Verify that the rsync distributor hasn't placed files
        sudo = '' if utils.is_root(self.cfg) else 'sudo '
        cmd = (sudo + 'ls -1 /home/{}'.format(ssh_user)).split()
        dirs = set(cli.Client(self.cfg).run(cmd).stdout.strip().split('\n'))
        self.assertNotIn('content', dirs)