Ejemplo n.º 1
0
    def test_all(self):
        """Publish the rpm rsync distributor before the yum distributor."""
        cfg = config.get_config()
        if selectors.bug_is_untestable(2187, cfg.version):
            self.skipTest('https://pulp.plan.io/issues/2187')

        # Create a user and a repository.
        ssh_user, priv_key = self.make_user(cfg)
        ssh_identity_file = self.write_private_key(cfg, priv_key)
        repo = self.make_repo(cfg, {'remote': {
            'host': urlparse(cfg.base_url).netloc,
            'root': '/home/' + ssh_user,
            'ssh_identity_file': ssh_identity_file,
            'ssh_user': ssh_user,
        }})

        # Publish with the rsync distributor.
        distribs = _get_dists_by_type_id(cfg, repo['_href'])
        self.verify_publish_is_skip(cfg, utils.publish_repo(
            cfg,
            repo,
            {'id': distribs['rpm_rsync_distributor']['id']}
        ).json())

        # Verify that the rsync distributor hasn't placed files
        sudo = '' if utils.is_root(cfg) else 'sudo '
        cmd = (sudo + 'ls -1 /home/{}'.format(ssh_user)).split()
        dirs = set(cli.Client(cfg).run(cmd).stdout.strip().split('\n'))
        self.assertNotIn('content', dirs)
Ejemplo n.º 2
0
def generate_repo_file(server_config, name, **kwargs):
    """Generate a repository file and returns its remote path.

    :param server_config: A :class:`pulp_smash.config.ServerConfig` object.
    :param name: file name and repo id (string inside []).
    :param kwargs: each item will be converted to repository properties where
        the key is the property name and the value its value.
    :returns: the remote path of the created repository file.
    """
    repo = StringIO()
    repo.write('[{}]\n'.format(name))
    path = os.path.join(
        '{}'.format('/etc/yum.repos.d/'), '{}.repo'.format(name))
    if 'name' not in kwargs:
        repo.write('{}: {}\n'.format('name', name))
    for key, value in kwargs.items():
        repo.write('{}: {}\n'.format(key, value))
    client = cli.Client(server_config)
    sudo = '' if is_root(server_config) else 'sudo '
    client.machine.session().run(
        'echo "{}" | {}tee {} > /dev/null'.format(
            repo.getvalue(),
            sudo,
            path
        )
    )
    repo.close()
    return path
def gen_yum_config_file(cfg, repositoryid, **kwargs):
    """Generate a yum configuration file and write it to ``/etc/yum.repos.d/``.

    Generate a yum configuration file containing a single repository section,
    and write it to ``/etc/yum.repos.d/{repositoryid}.repo``.

    :param pulp_smash.config.ServerConfig cfg: The system on which to create a
        yum configuration file.
    :param repositoryid: The section's ``repositoryid``. Used when naming the
        configuration file and populating the brackets at the head of the file.
        For details, see yum.conf(5).
    :param kwargs: Section options. Each kwarg corresponds to one option. For
        details, see yum.conf(5).
    :returns: The path to the yum configuration file.
    """
    path = os.path.join('/etc/yum.repos.d/', repositoryid + '.repo')
    with StringIO() as section:
        section.write('[{}]\n'.format(repositoryid))
        for key, value in kwargs.items():
            section.write('{}: {}\n'.format(key, value))
        cli.Client(cfg).machine.session().run(
            'echo "{}" | {}tee {} > /dev/null'
            .format(section.getvalue(), '' if is_root(cfg) else 'sudo ', path)
        )
    return path
Ejemplo n.º 4
0
def _set_pulp_manage_rsync(cfg, boolean):
    """Modify the ``pulp_manage_rsync`` SELinux policy.

    If the ``semanage`` executable is not available, return. Do this to deal
    with the possibility that SELinux is not installed on the system under
    test.

    For more information on the ``pulp_manage_rsync`` SELinux policy, see `ISO
    rsync Distributor → Configuration
    <http://docs.pulpproject.org/plugins/pulp_rpm/tech-reference/iso-rsync-distributor.html#configuration>`_.

    :param pulp_smash.config.ServerConfig cfg: Information about the system
        being modified.
    :param state: Either ``True`` or ``False``, indicating whether the
        ``pulp_manage_rsync`` SELinux policy should be turned on or off.
    :rtype: pulp_smash.cli.CompletedProcess
    """
    policy = 'pulp_manage_rsync'
    client = cli.Client(cfg)
    try:
        client.run(('which', 'semanage'))
    except exceptions.CalledProcessError:
        return
    cmd = [] if utils.is_root(cfg) else ['sudo']
    cmd.extend(['semanage', 'boolean', '--modify'])
    cmd.append('--on' if boolean else '--off')
    cmd.append(policy)
    return client.run(cmd)
Ejemplo n.º 5
0
    def test_force_sync(self):
        """Test whether one can force Pulp to perform a full sync."""
        cfg = config.get_config()
        if selectors.bug_is_untestable(1982, cfg.version):
            self.skipTest("https://pulp.plan.io/issues/1982")

        # Create and sync a repository.
        client = cli.Client(cfg)
        repo_id = utils.uuid4()
        client.run("pulp-admin rpm repo create --repo-id {} --feed {}".format(repo_id, RPM_SIGNED_FEED_URL).split())
        self.addCleanup(client.run, "pulp-admin rpm repo delete --repo-id {}".format(repo_id).split())
        sync_repo(cfg, repo_id)

        # Delete a random RPM
        rpms = self._list_rpms(cfg)
        client.run("{} rm -rf {}".format("sudo" if not is_root(cfg) else "", random.choice(rpms)).split())
        with self.subTest(comment="Verify the RPM was removed."):
            self.assertEqual(len(self._list_rpms(cfg)), len(rpms) - 1)

        # Sync the repository *without* force_sync.
        sync_repo(cfg, repo_id)
        with self.subTest(comment="Verify the RPM has not been restored."):
            self.assertEqual(len(self._list_rpms(cfg)), len(rpms) - 1)

        # Sync the repository again
        sync_repo(cfg, repo_id, force_sync=True)
        with self.subTest(comment="Verify the RPM has been restored."):
            self.assertEqual(len(self._list_rpms(cfg)), len(rpms))
Ejemplo n.º 6
0
    def verify_remote_units_path(self, cfg, distributor_cfg, num_units=None):
        """Verify the RPM rsync distributor has placed RPMs as appropriate.

        Verify that path ``{root}/{remote_units_path}/rpm/`` exists in the
        target system's filesystem, and that the correct number of RPMs are
        present in that directory.

        :param pulp_smash.config.PulpSmashConfig cfg: Information about the
            system onto which files have been published.
        :param distributor_cfg: A dict of information about an RPM rsync
            distributor.
        :param num_units: The number of units that should be on the target
            system's filesystem. Defaults to
            :data:`pulp_smash.constants.RPM_SIGNED_FEED_COUNT`.
        :returns: Nothing.
        """
        if num_units is None:
            num_units = RPM_SIGNED_FEED_COUNT
        cli_client = cli.Client(cfg)
        sudo = () if utils.is_root(cfg) else ('sudo', )
        path = distributor_cfg['config']['remote']['root']
        remote_units_path = (distributor_cfg['config'].get(
            'remote_units_path', 'content/units'))
        for segment in _split_path(remote_units_path):
            cmd = sudo + ('ls', '-1', path)
            files = set(cli_client.run(cmd).stdout.strip().split('\n'))
            self.assertIn(segment, files)
            path = os.path.join(path, segment)
        cmd = sudo + ('find', path, '-name', '*.rpm')
        files = cli_client.run(cmd).stdout.strip().split('\n')
        self.assertEqual(len(files), num_units, files)
Ejemplo n.º 7
0
    def write_private_key(self, cfg, private_key):
        """Write the given private key to a file on disk.

        Ensure that the file is owned by user "apache" and has permissions of
        ``600``. In addition, schedule the key for deletion with
        ``self.addCleanup``.

        :param pulp_smash.config.ServerConfig cfg: Information about the server
            being targeted.
        :returns: The path to the private key on disk, as a string.
        """
        sudo = '' if utils.is_root(cfg) else 'sudo '
        client = cli.Client(cfg)
        ssh_identity_file = client.run(['mktemp']).stdout.strip()
        self.addCleanup(client.run, (sudo + 'rm ' + ssh_identity_file).split())
        client.machine.session().run(
            "echo '{}' > {}".format(private_key, ssh_identity_file)
        )
        client.run(['chmod', '600', ssh_identity_file])
        client.run((sudo + 'chown apache ' + ssh_identity_file).split())
        # Pulp's SELinux policy requires files handled by Pulp to have the
        # httpd_sys_rw_content_t label
        enforcing = client.run(['getenforce']).stdout.strip()
        if enforcing.lower() != 'disabled':
            client.run(
                (sudo + 'chcon -t httpd_sys_rw_content_t ' + ssh_identity_file)
                .split()
            )
        return ssh_identity_file
def generate_content_source(server_config, name, **kwargs):
    """Generate a content source file and returns its remote path.

    See `Defining a Content Source`_ for more information.

    .. _Defining a Content Source:
        http://docs.pulpproject.org/user-guide/content-sources.html#defining-a-content-source

    :param server_config: A :class:`pulp_smash.config.ServerConfig` object.
    :param name: file name and content source id (string inside []).
    :param kwargs: each item will be converted to content source properties
        where the key is the property name and the value its value.
    :returns: the remote path of the created content source file.
    """
    content_source = StringIO()
    content_source.write('[{}]\n'.format(name))
    path = os.path.join(
        '{}'.format(CONTENT_SOURCES_PATH), '{}.conf'.format(name))
    if 'name' not in kwargs:
        content_source.write('{}: {}\n'.format('name', name))
    for key, value in kwargs.items():
        content_source.write('{}: {}\n'.format(key, value))
    client = cli.Client(server_config)
    sudo = '' if is_root(server_config) else 'sudo '
    client.machine.session().run(
        'echo "{}" | {}tee {} > /dev/null'.format(
            content_source.getvalue(),
            sudo,
            path
        )
    )
    content_source.close()
    return path
Ejemplo n.º 9
0
def gen_yum_config_file(cfg, repositoryid, **kwargs):
    """Generate a yum configuration file and write it to ``/etc/yum.repos.d/``.

    Generate a yum configuration file containing a single repository section,
    and write it to ``/etc/yum.repos.d/{repositoryid}.repo``.

    :param pulp_smash.config.PulpSmashConfig cfg: The system on which to create
        a yum configuration file.
    :param repositoryid: The section's ``repositoryid``. Used when naming the
        configuration file and populating the brackets at the head of the file.
        For details, see yum.conf(5).
    :param kwargs: Section options. Each kwarg corresponds to one option. For
        details, see yum.conf(5).
    :returns: The path to the yum configuration file.
    """
    path = os.path.join('/etc/yum.repos.d/', repositoryid + '.repo')
    with StringIO() as section:
        section.write('[{}]\n'.format(repositoryid))
        for key, value in kwargs.items():
            section.write('{}: {}\n'.format(key, value))
        cli.Client(cfg).machine.session().run(
            'echo "{}" | {}tee {} > /dev/null'.format(
                section.getvalue(), '' if utils.is_root(cfg) else 'sudo ',
                path))
    return path
Ejemplo n.º 10
0
    def write_private_key(self, cfg, private_key):
        """Write the given private key to a file on disk.

        Ensure that the file is owned by user "apache" and has permissions of
        ``600``. In addition, schedule the key for deletion with
        ``self.addCleanup``.

        :param pulp_smash.config.PulpSmashConfig cfg: Information about the
            host being targeted.
        :returns: The path to the private key on disk, as a string.
        """
        sudo = '' if utils.is_root(cfg) else 'sudo '
        client = cli.Client(cfg)
        ssh_identity_file = client.run(['mktemp']).stdout.strip()
        self.addCleanup(client.run, (sudo + 'rm ' + ssh_identity_file).split())
        client.machine.session().run("echo '{}' > {}".format(
            private_key, ssh_identity_file))
        client.run(['chmod', '600', ssh_identity_file])
        client.run((sudo + 'chown apache ' + ssh_identity_file).split())
        # Pulp's SELinux policy requires files handled by Pulp to have the
        # httpd_sys_rw_content_t label
        enforcing = client.run(['getenforce']).stdout.strip()
        if enforcing.lower() != 'disabled':
            client.run((sudo + 'chcon -t httpd_sys_rw_content_t ' +
                        ssh_identity_file).split())
        return ssh_identity_file
Ejemplo n.º 11
0
    def verify_remote_units_path(self, cfg, distributor_cfg):
        """Verify the RPM rsync distributor has placed RPMs as appropriate.

        Verify that path ``{root}/{remote_units_path}/rpm`` exists in the
        target system's filesystem, and that
        :data:`pulp_smash.constants.RPM_SIGNED_FEED_COUNT` RPMs are present in
        this directory.

        :param pulp_smash.config.ServerConfig cfg: Information about the system
            onto which files have been published.
        :param distributor_cfg: A dict of information about an RPM rsync
            distributor.
        :returns: Nothing.
        """
        # This method avoids calling command_string.split() to avoid issues
        # with spaces and other funny character in path names.
        cli_client = cli.Client(cfg)
        sudo = () if utils.is_root(cfg) else ('sudo',)
        path = distributor_cfg['config']['remote']['root']
        remote_units_path = distributor_cfg['config'].get(
            'remote_units_path',
            'content/units',
        )
        for segment in _split_path(remote_units_path):
            cmd = sudo + ('ls', '-1', path)
            files = set(cli_client.run(cmd).stdout.strip().split('\n'))
            self.assertIn(segment, files)
            path = os.path.join(path, segment)
        cmd = sudo + ('find', path, '-name', '*.rpm')
        files = cli_client.run(cmd).stdout.strip().split('\n')
        self.assertEqual(len(files), RPM_SIGNED_FEED_COUNT, files)
Ejemplo n.º 12
0
    def test_force_sync(self):
        """Test whether one can force Pulp to perform a full sync."""
        cfg = config.get_config()
        if selectors.bug_is_untestable(1982, cfg.version):
            self.skipTest('https://pulp.plan.io/issues/1982')

        # Create and sync a repository.
        client = cli.Client(cfg)
        repo_id = utils.uuid4()
        client.run('pulp-admin rpm repo create --repo-id {} --feed {}'.format(
            repo_id, RPM_SIGNED_FEED_URL).split())
        self.addCleanup(
            client.run,
            'pulp-admin rpm repo delete --repo-id {}'.format(repo_id).split())
        sync_repo(cfg, repo_id)

        # Delete a random RPM
        rpms = self._list_rpms(cfg)
        client.run('{} rm -rf {}'.format(
            'sudo' if not is_root(cfg) else '',
            random.choice(rpms),
        ).split())
        with self.subTest(comment='Verify the RPM was removed.'):
            self.assertEqual(len(self._list_rpms(cfg)), len(rpms) - 1)

        # Sync the repository *without* force_sync.
        sync_repo(cfg, repo_id)
        with self.subTest(comment='Verify the RPM has not been restored.'):
            self.assertEqual(len(self._list_rpms(cfg)), len(rpms) - 1)

        # Sync the repository again
        sync_repo(cfg, repo_id, force_sync=True)
        with self.subTest(comment='Verify the RPM has been restored.'):
            self.assertEqual(len(self._list_rpms(cfg)), len(rpms))
Ejemplo n.º 13
0
def set_pulp_manage_rsync(cfg, boolean):
    """Set the ``pulp_manage_rsync`` SELinux policy.

    If the ``semanage`` executable is not available, return. (This is the case
    if SELinux isn't installed on the system under test.) Otherwise, set the
    ``pulp_manage_rsync SELinux policy on or off, depending on the truthiness
    of ``boolean``.

    For more information on the ``pulp_manage_rsync`` SELinux policy, see `ISO
    rsync Distributor → Configuration
    <http://docs.pulpproject.org/plugins/pulp_rpm/tech-reference/iso-rsync-distributor.html#configuration>`_.

    :param pulp_smash.config.PulpSmashConfig cfg: Information about a Pulp
        host.
    :param boolean: Either ``True`` or ``False``.
    :returns: Information about the executed command, or ``None`` if no command
        was executed.
    :rtype: pulp_smash.cli.CompletedProcess
    """
    sudo = () if utils.is_root(cfg) else ('sudo', )
    client = cli.Client(cfg)
    try:
        # semanage is installed at /sbin/semanage on some distros, and requires
        # root privileges to discover.
        client.run(sudo + ('which', 'semanage'))
    except exceptions.CalledProcessError:
        return None
    cmd = sudo
    cmd += ('semanage', 'boolean', '--modify')
    cmd += ('--on', ) if boolean else ('--off', )
    cmd += ('pulp_manage_rsync', )
    return client.run(cmd)
 def setUpClass(cls):
     """Create a content source."""
     super(RefreshAndDeleteContentSourcesTestCase, cls).setUpClass()
     cls.cfg = config.get_config()
     if cls.cfg.version < Version('2.8.6'):
         raise unittest.SkipTest('This test requires at least 2.8.6')
     pulp_admin_login(cls.cfg)
     cls.client = cli.Client(cls.cfg)
     cls.content_source_id = uuid4()
     content_source_path = generate_content_source(
         cls.cfg,
         cls.content_source_id,
         enabled='1',
         type='yum',
         base_url=RPM_SIGNED_FEED_URL,
     )
     sudo = '' if is_root(cls.cfg) else 'sudo '
     cls.responses = [
         cls.client.run(
             'pulp-admin content sources refresh'.split()
         ),
         _get_content_source_ids(cls.cfg),
         cls.client.run(
             'pulp-admin content sources refresh --source-id {}'
             .format(cls.content_source_id).split()
         ),
     ]
     cls.client.run(
         '{}rm -f {}'.format(sudo, content_source_path).split())
     cls.responses.append(_get_content_source_ids(cls.cfg))
    def verify_remote_units_path(self, cfg, distributor_cfg):
        """Verify the RPM rsync distributor has placed RPMs as appropriate.

        Verify that path ``{root}/{remote_units_path}/rpm`` exists in the
        target system's filesystem, and that
        :data:`pulp_smash.constants.RPM_SIGNED_FEED_COUNT` RPMs are present in
        this directory.

        :param pulp_smash.config.ServerConfig cfg: Information about the system
            onto which files have been published.
        :param distributor_cfg: A dict of information about an RPM rsync
            distributor.
        :returns: Nothing.
        """
        # This method avoids calling command_string.split() to avoid issues
        # with spaces and other funny character in path names.
        cli_client = cli.Client(cfg)
        sudo = () if utils.is_root(cfg) else ('sudo', )
        path = distributor_cfg['config']['remote']['root']
        remote_units_path = distributor_cfg['config'].get(
            'remote_units_path',
            'content/units',
        )
        for segment in _split_path(remote_units_path):
            cmd = sudo + ('ls', '-1', path)
            files = set(cli_client.run(cmd).stdout.strip().split('\n'))
            self.assertIn(segment, files)
            path = os.path.join(path, segment)
        cmd = sudo + ('find', path, '-name', '*.rpm')
        files = cli_client.run(cmd).stdout.strip().split('\n')
        self.assertEqual(len(files), RPM_SIGNED_FEED_COUNT, files)
    def test_all(self):
        """Publish the rpm rsync distributor before the yum distributor."""
        cfg = config.get_config()
        if selectors.bug_is_untestable(2187, cfg.version):
            self.skipTest('https://pulp.plan.io/issues/2187')

        # Create a user and a repository.
        ssh_user, priv_key = self.make_user(cfg)
        ssh_identity_file = self.write_private_key(cfg, priv_key)
        repo_href = self.make_repo(
            cfg, {
                'remote': {
                    'host': urlparse(cfg.base_url).netloc,
                    'root': '/home/' + ssh_user,
                    'ssh_identity_file': ssh_identity_file,
                    'ssh_user': ssh_user,
                }
            })

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

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

        Return the former if root, and the latter if not.
        """
        if self.__sudo is None:
            self.__sudo = '' if utils.is_root(self.cfg) else 'sudo '
        return self.__sudo
Ejemplo n.º 18
0
    def sudo(self):
        """Return either ``''`` or ``'sudo '``.

        Return the former if root, and the latter if not.
        """
        if self.__sudo is None:
            self.__sudo = '' if utils.is_root(self.cfg) else 'sudo '
        return self.__sudo
Ejemplo n.º 19
0
 def setUpClass(cls):
     """Get all of the processes running on the target Pulp system."""
     cfg = config.get_config()
     cmd = [] if utils.is_root(config.get_config()) else ['sudo']
     cmd.extend(('ps', '-A', '-w', '-w', '-o', ','.join(PS_FIELDS)))
     cls.procs = [
         Process(*line.split(maxsplit=1))
         for line in cli.Client(cfg).run(cmd).stdout.splitlines()
     ]
    def tearDown(self):
        """Reset the number of Pul pworkers, and reset Pulp.

        Reset Pulp because :meth:`test_all` may break Pulp.
        """
        sudo = () if utils.is_root(self.cfg) else ('sudo', )
        # Delete last line from file.
        cli.Client(self.cfg).run(sudo + ('sed', '-i', '$d', _PULP_WORKERS_CFG))
        utils.reset_pulp(self.cfg)
 def setUp(self):
     """Ensure there is only one Pulp worker."""
     self.cfg = config.get_config()
     if selectors.bug_is_untestable(2835, self.cfg.pulp_version):
         self.skipTest('https://pulp.plan.io/issues/2835')
     sudo = '' if utils.is_root(self.cfg) else 'sudo'
     cli.Client(self.cfg).machine.session().run(
         "{} bash -c 'echo PULP_CONCURRENCY=1 >> {}'".format(
             sudo, _PULP_WORKERS_CFG))
     cli.GlobalServiceManager(self.cfg).restart(PULP_SERVICES)
Ejemplo n.º 22
0
 def test_dry_run(self):
     """Make sure pulp-manage-db runs if --dry-run is passed."""
     if selectors.bug_is_untestable(2776, self.cfg.pulp_version):
         self.skipTest('https://pulp.plan.io/issues/2776')
     cmd = () if utils.is_root(self.cfg) else ('sudo',)
     cmd += (
         'runuser', '--shell', '/bin/sh', '--command',
         'pulp-manage-db --dry-run', '-', 'apache'
     )
     cli.Client(self.cfg).run(cmd)
    def test_all(self):
        """Use the ``force_full`` RPM rsync distributor option."""
        cfg = config.get_config()
        api_client = api.Client(cfg)
        cli_client = cli.Client(cfg)
        sudo = '' if utils.is_root(cfg) else 'sudo '

        # Create a user and repo with an importer and distribs. Sync the repo.
        ssh_user, priv_key = self.make_user(cfg)
        ssh_identity_file = self.write_private_key(cfg, priv_key)
        repo_href = self.make_repo(
            cfg, {
                'remote': {
                    'host': urlparse(cfg.base_url).netloc,
                    'root': '/home/' + ssh_user,
                    'ssh_identity_file': ssh_identity_file,
                    'ssh_user': ssh_user,
                }
            })
        utils.sync_repo(cfg, repo_href)

        # Publish the repo with the yum and rsync distributors, respectively.
        # Verify that the RPM rsync distributor has placed files.
        distribs = _get_dists_by_type_id(cfg, repo_href)
        self.maybe_disable_selinux(cfg, 2199)
        for type_id in ('yum_distributor', 'rpm_rsync_distributor'):
            api_client.post(urljoin(repo_href, 'actions/publish/'),
                            {'id': distribs[type_id]['id']})
        self.verify_remote_units_path(cfg, distribs['rpm_rsync_distributor'])

        # Remove all files from the target directory, and publish again. Verify
        # that the RPM rsync distributor didn't place any files.
        cmd = sudo + 'rm -rf /home/{}/content'.format(ssh_user)
        cli_client.run(cmd.split())
        self.verify_publish_is_skip(
            cfg,
            api_client.post(urljoin(repo_href, 'actions/publish/'), {
                'id': distribs['rpm_rsync_distributor']['id']
            }).json())
        cmd = sudo + 'ls -1 /home/{}'.format(ssh_user)
        dirs = set(cli_client.run(cmd.split()).stdout.strip().split('\n'))
        self.assertNotIn('content', dirs)

        # Publish the repo with ``force_full`` set to true. Verify that the RPM
        # rsync distributor placed files.
        if selectors.bug_is_untestable(2202, cfg.version):
            return
        api_client.post(
            urljoin(repo_href, 'actions/publish/'), {
                'id': distribs['rpm_rsync_distributor']['id'],
                'override_config': {
                    'force_full': True
                },
            })
        self.verify_remote_units_path(cfg, distribs['rpm_rsync_distributor'])
Ejemplo n.º 24
0
    def test_all(self):
        """Test whether copied files retain their original mtime.

        This test targets the following issues:

        * `Pulp #2783 <https://pulp.plan.io/issues/2783>`_
        * `Pulp Smash #720 <https://github.com/PulpQE/pulp-smash/issues/720>`_

        Do the following:

        1. Create, sync and publish a repository, with ``generate_sqlite`` set
           to true.
        2. Get the ``mtime`` of the sqlite files.
        3. Upload an RPM package into the repository, and sync the repository.
        4. Get the ``mtime`` of the sqlite files again. Verify that the mtimes
           are the same.
        """
        cfg = config.get_config()
        if selectors.bug_is_untestable(2783, cfg.pulp_version):
            self.skipTest('https://pulp.plan.io/issues/2783')

        # Create, sync and publish a repository.
        client = api.Client(cfg, api.json_handler)
        body = gen_repo()
        body['importer_config']['feed'] = RPM_UNSIGNED_FEED_URL
        body['distributors'] = [gen_distributor()]
        body['distributors'][0]['distributor_config']['generate_sqlite'] = True
        repo = client.post(REPOSITORY_PATH, body)
        self.addCleanup(client.delete, repo['_href'])
        repo = client.get(repo['_href'], params={'details': True})
        utils.sync_repo(cfg, repo)
        utils.publish_repo(cfg, repo)

        # Get the mtime of the sqlite files.
        cli_client = cli.Client(cfg, cli.echo_handler)
        cmd = '' if utils.is_root(cfg) else 'sudo '
        cmd += "bash -c \"stat --format %Y '{}'/*\"".format(
            os.path.join(
                _PATH,
                repo['distributors'][0]['config']['relative_url'],
                'repodata',
            ))
        mtimes_pre = (
            cli_client.machine.session().run(cmd)[1].strip().split().sort())

        # Upload to the repo, and sync it.
        rpm = utils.http_get(RPM_SIGNED_URL)
        utils.upload_import_unit(cfg, rpm, {'unit_type_id': 'rpm'}, repo)
        utils.sync_repo(cfg, repo)

        # Get the mtime of the sqlite files again.
        time.sleep(1)
        mtimes_post = (
            cli_client.machine.session().run(cmd)[1].strip().split().sort())
        self.assertEqual(mtimes_pre, mtimes_post)
Ejemplo n.º 25
0
 def _verify_files_not_in_dir(self, cfg, distributor_cfg):
     """Verify no RPMs are in the distributor's ``remote_units_path``."""
     path = os.path.join(
         distributor_cfg['config']['remote']['root'],
         distributor_cfg['config'].get('remote_units_path', 'content/units')
     )
     cmd = ['find', path, '-name', '*.rpm']
     if not utils.is_root(cfg):
         cmd.insert(0, 'sudo')
     files = cli.Client(cfg).run(cmd).stdout.strip().split('\n')
     self.assertEqual(len(files), 0, files)
 def _verify_files_not_in_dir(self, cfg, *, yum_distributor,
                              rpm_rsync_distributor):
     """Verify no RPMs are in the distributor's ``relative_url`` dir."""
     path = os.path.join(
         rpm_rsync_distributor['config']['remote']['root'],
         yum_distributor['config']['relative_url'],
     )
     cmd = ['find', path, '-name', '*.rpm']
     if not utils.is_root(cfg):
         cmd.insert(0, 'sudo')
     files = cli.Client(cfg).run(cmd).stdout.strip().split('\n')
     self.assertEqual(files, [''])  # strange, but correct
Ejemplo n.º 27
0
 def setUpClass(cls):
     """Maybe skip this test case."""
     if inspect.getmro(cls)[0] == BaseTestCase:
         raise unittest.SkipTest('Abstract base class.')
     cls.cfg = config.get_config()
     if selectors.bug_is_untestable(2186, cls.cfg.pulp_version):
         raise unittest.SkipTest('https://pulp.plan.io/issues/2186')
     cls.cmd = () if utils.is_root(cls.cfg) else ('sudo',)
     cls.cmd += (
         'runuser', '--shell', '/bin/sh', '--command', 'pulp-manage-db',
         '-', 'apache'
     )
Ejemplo n.º 28
0
    def test_all(self):
        """Test Pulp's handling of its ``PULP_MAX_TASKS_PER_CHILD`` setting."""
        cfg = config.get_config()
        if selectors.bug_is_untestable(2172, cfg.version):
            self.skipTest('https://pulp.plan.io/issues/2172')
        set_opt = [
            'sed', '-i', '-e',
            's/.*PULP_MAX_TASKS_PER_CHILD=[0-9]*$/PULP_MAX_TASKS_PER_CHILD=2/',
            '/etc/default/pulp_workers'
        ]
        reset_opt = [
            'sed', '-i', '-e',
            's/^PULP_MAX_TASKS_PER_CHILD=2$/# PULP_MAX_TASKS_PER_CHILD=2/',
            '/etc/default/pulp_workers'
        ]
        if not utils.is_root(cfg):
            for cmd in (set_opt, reset_opt):
                cmd.insert(0, 'sudo')

        # Step 1
        for proc in get_pulp_worker_procs(cfg):
            self.assertNotIn('--maxtasksperchild=2', proc)

        # Step 2
        client = cli.Client(cfg)
        client.run(set_opt)
        self.addCleanup(client.run, reset_opt)
        restart_pulp(cfg)
        for proc in get_pulp_worker_procs(cfg):
            self.assertIn('--maxtasksperchild=2', proc)

        # Step 3
        repo_id = utils.uuid4()
        proc = client.run(
            'pulp-admin rpm repo create --repo-id {} --feed {}'
            .format(repo_id, RPM_UNSIGNED_FEED_URL).split()
        )
        self.addCleanup(
            client.run,
            'pulp-admin rpm repo delete --repo-id {}'.format(repo_id).split()
        )
        self.assertNotIn('Task Failed', proc.stdout)
        proc = client.run(
            'pulp-admin rpm repo sync run --repo-id {}'.format(repo_id).split()
        )
        self.assertNotIn('Task Failed', proc.stdout)

        # Step 4
        client.run(reset_opt)
        restart_pulp(cfg)
        for proc in get_pulp_worker_procs(cfg):
            self.assertNotIn('--maxtasksperchild=2', proc)
Ejemplo n.º 29
0
    def test_all(self):
        """Check for content synced from a feed with PULP_DISTRIBUTION.xml."""
        if self.cfg.pulp_version < version.Version('2.11.2'):
            self.skipTest(
                'PULP_DISTRIBUTION.xml improved parsing is available on Pulp '
                '2.11.2+')
        client = api.Client(self.cfg, api.json_handler)
        distributor = gen_distributor()
        distributor['auto_publish'] = True
        body = gen_repo()
        body['distributors'] = [distributor]
        body['importer_config'] = {
            'feed': RPM_WITH_PULP_DISTRIBUTION_FEED_URL,
        }
        repo = client.post(REPOSITORY_PATH, body)
        self.addCleanup(client.delete, repo['_href'])
        utils.sync_repo(self.cfg, repo)
        repo = client.get(repo['_href'], params={'details': True})
        self.assertEqual(repo['content_unit_counts']['distribution'], 1)
        cli_client = cli.Client(self.cfg, cli.code_handler)
        relative_url = repo['distributors'][0]['config']['relative_url']
        sudo = () if utils.is_root(self.cfg) else ('sudo', )
        pulp_distribution = cli_client.run(sudo + (
            'cat',
            os.path.join(
                '/var/lib/pulp/published/yum/http/repos/',
                relative_url,
                'PULP_DISTRIBUTION.xml',
            ),
        )).stdout
        # make sure published repository PULP_DISTRIBUTION.xml does not include
        # any extra file from the original repo's PULP_DISTRIBUTION.xml under
        # metadata directory
        self.assertNotIn('metadata/productid', pulp_distribution)

        release_info = cli_client.run(sudo + (
            'cat',
            os.path.join(
                '/var/lib/pulp/published/yum/http/repos/',
                relative_url,
                'release-notes/release-info',
            ),
        )).stdout
        response = requests.get(
            urljoin(
                urljoin(RPM_WITH_PULP_DISTRIBUTION_FEED_URL, 'release-notes/'),
                'release-info',
            ))
        # make sure published repository has extra files outside the metadata
        # directory from the origiginal repo's PULP_DISTRIBUTION.xml
        self.assertEqual(release_info, response.text)
Ejemplo n.º 30
0
    def setUpClass(cls):
        """Create an RPM repository and issue a task to download the repo.

        Do the following:

        1. Reset Pulp.
        2. Create a repository with the "on demand" download policy.
        3. Sync and publish the repository.
        4. Trigger a repository download.
        5. Corrupt a file in the repository.
        6. Trigger a repository download, without unit verification.
        7. Trigger a repository download, with unit verification.
        """
        super(FixFileCorruptionTestCase, cls).setUpClass()
        if (selectors.bug_is_untestable(1905, cls.cfg.version)
                and _os_is_rhel6(cls.cfg)):
            raise unittest.SkipTest('https://pulp.plan.io/issues/1905')

        # Ensure Pulp is empty of units otherwise we might just associate pre-
        # existing units.
        utils.reset_pulp(cls.cfg)

        # Create, sync and publish a repository.
        repo = _create_repo(cls.cfg, 'on_demand')
        cls.resources.add(repo['_href'])
        utils.sync_repo(cls.cfg, repo['_href'])

        # Trigger a repository download. Read the repo before and after.
        api_client = api.Client(cls.cfg, api.json_handler)
        download_path = urljoin(repo['_href'], 'actions/download/')
        params = {'details': True}
        cls.repo_pre_download = api_client.get(repo['_href'], params=params)
        api_client.post(download_path, {'verify_all_units': False})
        cls.repo_post_download = api_client.get(repo['_href'], params=params)

        # Corrupt an RPM. The file is there, but the checksum isn't right.
        rpm_abs_path = cls.get_rpm_abs_path()
        cli_client = cli.Client(cls.cfg)
        sudo = '' if utils.is_root(cls.cfg) else 'sudo '
        checksum_cmd = (sudo + 'sha256sum ' + rpm_abs_path).split()
        cls.sha_pre_corruption = cli_client.run(checksum_cmd).stdout.strip()
        cli_client.run((sudo + 'rm ' + rpm_abs_path).split())
        cli_client.run((sudo + 'touch ' + rpm_abs_path).split())
        cli_client.run((sudo + 'chown apache:apache ' + rpm_abs_path).split())
        cls.sha_post_corruption = cli_client.run(checksum_cmd).stdout.strip()

        # Trigger repository downloads that don't and do checksum files, resp.
        api_client.post(download_path, {'verify_all_units': False})
        cls.unverified_file_sha = cli_client.run(checksum_cmd).stdout.strip()
        api_client.post(download_path, {'verify_all_units': True})
        cls.verified_file_sha = cli_client.run(checksum_cmd).stdout.strip()
    def setUpClass(cls):
        """Create an RPM repository and issue a task to download the repo.

        Do the following:

        1. Reset Pulp.
        2. Create a repository with the "on demand" download policy.
        3. Sync and publish the repository.
        4. Trigger a repository download.
        5. Corrupt a file in the repository.
        6. Trigger a repository download, without unit verification.
        7. Trigger a repository download, with unit verification.
        """
        super(FixFileCorruptionTestCase, cls).setUpClass()
        if (selectors.bug_is_untestable(1905, cls.cfg.version) and
                _os_is_rhel6(cls.cfg)):
            raise unittest.SkipTest('https://pulp.plan.io/issues/1905')

        # Ensure Pulp is empty of units otherwise we might just associate pre-
        # existing units.
        utils.reset_pulp(cls.cfg)

        # Create, sync and publish a repository.
        repo = _create_repo(cls.cfg, 'on_demand')
        cls.resources.add(repo['_href'])
        utils.sync_repo(cls.cfg, repo['_href'])

        # Trigger a repository download. Read the repo before and after.
        api_client = api.Client(cls.cfg, api.json_handler)
        download_path = urljoin(repo['_href'], 'actions/download/')
        params = {'details': True}
        cls.repo_pre_download = api_client.get(repo['_href'], params=params)
        api_client.post(download_path, {'verify_all_units': False})
        cls.repo_post_download = api_client.get(repo['_href'], params=params)

        # Corrupt an RPM. The file is there, but the checksum isn't right.
        rpm_abs_path = cls.get_rpm_abs_path()
        cli_client = cli.Client(cls.cfg)
        sudo = '' if utils.is_root(cls.cfg) else 'sudo '
        checksum_cmd = (sudo + 'sha256sum ' + rpm_abs_path).split()
        cls.sha_pre_corruption = cli_client.run(checksum_cmd).stdout.strip()
        cli_client.run((sudo + 'rm ' + rpm_abs_path).split())
        cli_client.run((sudo + 'touch ' + rpm_abs_path).split())
        cli_client.run((sudo + 'chown apache:apache ' + rpm_abs_path).split())
        cls.sha_post_corruption = cli_client.run(checksum_cmd).stdout.strip()

        # Trigger repository downloads that don't and do checksum files, resp.
        api_client.post(download_path, {'verify_all_units': False})
        cls.unverified_file_sha = cli_client.run(checksum_cmd).stdout.strip()
        api_client.post(download_path, {'verify_all_units': True})
        cls.verified_file_sha = cli_client.run(checksum_cmd).stdout.strip()
Ejemplo n.º 32
0
def get_pulp_worker_procs(cfg):
    """Use ``ps aux`` to get information about each Pulp worker process.

    :param pulp_smash.config.ServerConfig cfg: Information about the Pulp
        server being targeted.
    :return: An iterable of strings, one per line of matching output.
    """
    cmd = ['ps', 'aux']
    if not utils.is_root(cfg):
        cmd.insert(0, 'sudo')
    return tuple((
        proc for proc in cli.Client(cfg).run(cmd).stdout.splitlines()
        if 'celery worker' in proc and 'resource_manager' not in proc
    ))
Ejemplo n.º 33
0
    def test_all(self):
        """Test whether one can force Pulp to perform a full sync."""
        cfg = config.get_config()
        if selectors.bug_is_untestable(1982, cfg.pulp_version):
            self.skipTest('https://pulp.plan.io/issues/1982')

        # Create and sync a repository.
        client = cli.Client(cfg)
        repo_id = utils.uuid4()
        client.run((
            'pulp-admin',
            'rpm',
            'repo',
            'create',
            '--repo-id',
            repo_id,
            '--feed',
            RPM_UNSIGNED_FEED_URL,
        ))
        self.addCleanup(client.run, (
            'pulp-admin',
            'rpm',
            'repo',
            'delete',
            '--repo-id',
            repo_id,
        ))
        sync_repo(cfg, repo_id)

        # Delete a random RPM from the filesystem.
        rpms = self._list_rpms(cfg)
        rpm = random.choice(rpms)
        cmd = []
        if not is_root(cfg):
            cmd.append('sudo')
        cmd.extend(('rm', '-rf', rpm))
        client.run(cmd)
        with self.subTest(comment='verify the rpm has been removed'):
            self.assertEqual(len(self._list_rpms(cfg)), len(rpms) - 1, rpm)

        # Sync the repository without --force-full.
        sync_repo(cfg, repo_id)
        with self.subTest(comment='verify the rpm has not yet been restored'):
            self.assertEqual(len(self._list_rpms(cfg)), len(rpms) - 1, rpm)

        # Sync the repository with --force-full.
        sync_repo(cfg, repo_id, force_sync=True)
        with self.subTest(comment='verify the rpm has been restored'):
            self.assertEqual(len(self._list_rpms(cfg)), len(rpms), rpm)
Ejemplo n.º 34
0
    def test_all(self):
        """Use the ``force_full`` RPM rsync distributor option."""
        cfg = config.get_config()
        api_client = api.Client(cfg)
        cli_client = cli.Client(cfg)
        sudo = '' if utils.is_root(cfg) else 'sudo '

        # Create a user and repo with an importer and distribs. Sync the repo.
        ssh_user, priv_key = self.make_user(cfg)
        ssh_identity_file = self.write_private_key(cfg, priv_key)
        repo_href = self.make_repo(cfg, {'remote': {
            'host': urlparse(cfg.base_url).netloc,
            'root': '/home/' + ssh_user,
            'ssh_identity_file': ssh_identity_file,
            'ssh_user': ssh_user,
        }})
        utils.sync_repo(cfg, repo_href)

        # Publish the repo with the yum and rsync distributors, respectively.
        # Verify that the RPM rsync distributor has placed files.
        distribs = _get_dists_by_type_id(cfg, repo_href)
        self.maybe_disable_selinux(cfg, 2199)
        for type_id in ('yum_distributor', 'rpm_rsync_distributor'):
            api_client.post(urljoin(repo_href, 'actions/publish/'), {
                'id': distribs[type_id]['id']
            })
        self.verify_files_in_dir(cfg, distribs['rpm_rsync_distributor'])

        # Remove all files from the target directory, and publish again. Verify
        # that the RPM rsync distributor didn't place any files.
        cmd = sudo + 'rm -rf /home/{}/content'.format(ssh_user)
        cli_client.run(cmd.split())
        self.verify_publish_is_skip(cfg, api_client.post(
            urljoin(repo_href, 'actions/publish/'),
            {'id': distribs['rpm_rsync_distributor']['id']}
        ).json())
        cmd = sudo + 'ls -1 /home/{}'.format(ssh_user)
        dirs = set(cli_client.run(cmd.split()).stdout.strip().split('\n'))
        self.assertNotIn('content', dirs)

        # Publish the repo with ``force_full`` set to true. Verify that the RPM
        # rsync distributor placed files.
        if selectors.bug_is_untestable(2202, cfg.version):
            return
        api_client.post(urljoin(repo_href, 'actions/publish/'), {
            'id': distribs['rpm_rsync_distributor']['id'],
            'override_config': {'force_full': True},
        })
        self.verify_files_in_dir(cfg, distribs['rpm_rsync_distributor'])
Ejemplo n.º 35
0
 def _verify_files_not_in_dir(
         self,
         cfg,
         *,
         yum_distributor,
         rpm_rsync_distributor):
     """Verify no RPMs are in the distributor's ``relative_url`` dir."""
     path = os.path.join(
         rpm_rsync_distributor['config']['remote']['root'],
         yum_distributor['config']['relative_url'],
     )
     cmd = ['find', path, '-name', '*.rpm']
     if not utils.is_root(cfg):
         cmd.insert(0, 'sudo')
     files = cli.Client(cfg).run(cmd).stdout.strip().split('\n')
     self.assertEqual(files, [''])  # strange, but correct
    def make_user(self, cfg):
        """Create a user account with a home directory and an SSH keypair.

        In addition, schedule the user for deletion with ``self.addCleanup``.

        :param pulp_smash.config.ServerConfig cfg: Information about the server
            being targeted.
        :returns: A ``(username, private_key)`` tuple.
        """
        sudo = '' if utils.is_root(cfg) else 'sudo '
        creator = _make_user(cfg)
        username = next(creator)
        self.addCleanup(
            cli.Client(cfg).run,
            (sudo + 'userdel --remove {}').format(username).split())
        private_key = next(creator)
        return (username, private_key)
    def test_all(self):
        """Update an RPM in a repository and on a host."""
        cfg = config.get_config()
        if check_issue_2277(cfg):
            raise unittest.SkipTest('https://pulp.plan.io/issues/2277')
        client = cli.Client(cfg)
        sudo = '' if is_root(cfg) else 'sudo '

        # Create the second repository.
        repo_id = self.create_repo(cfg)

        # Pick an RPM with two versions.
        rpm_name = 'walrus'
        rpm_versions = _get_rpm_names_versions(cfg, _REPO_ID)[rpm_name]

        # Copy the older RPM to the second repository, and publish it.
        self._copy_and_publish(cfg, rpm_name, rpm_versions[0], repo_id)

        # Install the RPM on a host.
        repo_path = gen_yum_config_file(
            cfg,
            baseurl=urljoin(cfg.base_url, 'pulp/repos/' + repo_id),
            enabled=1,
            gpgcheck=0,
            metadata_expire=0,  # force metadata to load every time
            repositoryid=repo_id,
            sslverify='yes' if cfg.verify else 'no',
        )
        self.addCleanup(
            client.run,
            '{}rm {}'.format(sudo, repo_path).split()
        )
        client.run('{}yum install -y {}'.format(sudo, rpm_name).split())
        self.addCleanup(
            client.run,
            '{}yum remove -y {}'.format(sudo, rpm_name).split()
        )
        client.run(['rpm', '-q', rpm_name])

        # Copy the newer RPM to the second repository, and publish it.
        self._copy_and_publish(cfg, rpm_name, rpm_versions[1], repo_id)

        # Update the installed RPM on the host.
        proc = client.run('{}yum -y update {}'.format(sudo, rpm_name).split())
        self.assertNotIn('Nothing to do.', proc.stdout)
Ejemplo n.º 38
0
    def maybe_disable_selinux(self, cfg, pulp_issue_id):
        """Disable SELinux if appropriate.

        If the given Pulp issue is unresolved, and if SELinux is installed and
        enforcing on the target Pulp system, then disable SELinux and schedule
        it to be re-enabled. (Method ``addCleanup`` is used for the schedule.)

        :param pulp_smash.config.ServerConfig cfg: Information about the Pulp
            server being targeted.
        :param pulp_issue_id: The (integer) ID of a `Pulp issue`_. If the
            referenced issue is fixed in the Pulp system under test, this
            method immediately returns.
        :returns: Nothing.

        .. _Pulp issue: https://pulp.plan.io/issues/
        """
        # Abort if the Pulp issue is resolved, if SELinux is not installed or
        # if SELinux is not enforcing.
        #
        # NOTE: Hard-coding the absolute path to a command is a Bad Idea™.
        # However, non-login non-root shells may have short PATH environment
        # variables. For example:
        #
        #     /usr/lib64/qt-3.3/bin:/usr/local/bin:/usr/bin
        #
        # We cannot execute `PATH=${PATH}:/usr/sbin which getenforce` because
        # Plumbum does a good job of preventing shell expansions. See:
        # https://github.com/PulpQE/pulp-smash/issues/89
        if selectors.bug_is_testable(pulp_issue_id, cfg.version):
            return
        client = cli.Client(cfg, cli.echo_handler)
        cmd = 'test -e /usr/sbin/getenforce'.split()
        if client.run(cmd).returncode != 0:
            return
        client.response_handler = cli.code_handler
        cmd = ['/usr/sbin/getenforce']
        if client.run(cmd).stdout.strip().lower() != 'enforcing':
            return

        # Temporarily disable SELinux.
        sudo = '' if utils.is_root(cfg) else 'sudo '
        cmd = (sudo + 'setenforce 0').split()
        client.run(cmd)
        cmd = (sudo + 'setenforce 1').split()
        self.addCleanup(client.run, cmd)
Ejemplo n.º 39
0
    def maybe_disable_selinux(self, cfg, pulp_issue_id):
        """Disable SELinux if appropriate.

        If the given Pulp issue is unresolved, and if SELinux is installed and
        enforcing on the target Pulp system, then disable SELinux and schedule
        it to be re-enabled. (Method ``addCleanup`` is used for the schedule.)

        :param pulp_smash.config.PulpSmashConfig cfg: Information about the
            Pulp deployment being targeted.
        :param pulp_issue_id: The (integer) ID of a `Pulp issue`_. If the
            referenced issue is fixed in the Pulp system under test, this
            method immediately returns.
        :returns: Nothing.

        .. _Pulp issue: https://pulp.plan.io/issues/
        """
        # Abort if the Pulp issue is resolved, if SELinux is not installed or
        # if SELinux is not enforcing.
        #
        # NOTE: Hard-coding the absolute path to a command is a Bad Idea™.
        # However, non-login non-root shells may have short PATH environment
        # variables. For example:
        #
        #     /usr/lib64/qt-3.3/bin:/usr/local/bin:/usr/bin
        #
        # We cannot execute `PATH=${PATH}:/usr/sbin which getenforce` because
        # Plumbum does a good job of preventing shell expansions. See:
        # https://github.com/PulpQE/pulp-smash/issues/89
        if selectors.bug_is_testable(pulp_issue_id, cfg.pulp_version):
            return
        client = cli.Client(cfg, cli.echo_handler)
        cmd = 'test -e /usr/sbin/getenforce'.split()
        if client.run(cmd).returncode != 0:
            return
        client.response_handler = cli.code_handler
        cmd = ['/usr/sbin/getenforce']
        if client.run(cmd).stdout.strip().lower() != 'enforcing':
            return

        # Temporarily disable SELinux.
        sudo = '' if utils.is_root(cfg) else 'sudo '
        cmd = (sudo + 'setenforce 0').split()
        client.run(cmd)
        cmd = (sudo + 'setenforce 1').split()
        self.addCleanup(client.run, cmd)
Ejemplo n.º 40
0
    def test_all(self):
        """Test puppet_install_distributor.

        Do the following:

        1. Create a puppet repository with a puppet_install_distributor
        2. Upload a puppet module
        3. Publish the repository
        4. Check if the puppet_install_distributor config was properly used
        """
        cli_client = cli.Client(self.cfg)
        sudo = () if utils.is_root(self.cfg) else ('sudo', )

        # Create a directory and make sure Pulp can write to it.
        install_path = cli_client.run(('mktemp', '--directory')).stdout.strip()
        self.addCleanup(cli_client.run, sudo + ('rm', '-rf', install_path))
        cli_client.run(sudo + ('chown', 'apache:apache', install_path))
        cli_client.run(sudo + ('chcon', '-t', 'puppet_etc_t', install_path))

        # Make sure the pulp_manage_puppet boolean is enabled
        cli_client.run(sudo + ('semanage', 'boolean', '--modify', '--on',
                               'pulp_manage_puppet'))
        self.addCleanup(
            cli_client.run, sudo +
            ('semanage', 'boolean', '--modify', '--off', 'pulp_manage_puppet'))

        # Create and populate a Puppet repository.
        distributor = gen_install_distributor()
        distributor['distributor_config']['install_path'] = install_path
        body = gen_repo()
        body['distributors'] = [distributor]
        client = api.Client(self.cfg, api.json_handler)
        repo = client.post(REPOSITORY_PATH, body)
        self.addCleanup(client.delete, repo['_href'])
        repo = client.get(repo['_href'], params={'details': True})
        unit = utils.http_get(PUPPET_MODULE_URL_1)
        utils.upload_import_unit(self.cfg, unit,
                                 {'unit_type_id': 'puppet_module'}, repo)

        # Publish, and verify the module is present. (Dir has 700 permissions.)
        utils.publish_repo(self.cfg, repo)
        proc = cli_client.run(sudo +
                              ('runuser', '--shell', '/bin/sh', '--command',
                               'ls -1 {}'.format(install_path), '-', 'apache'))
        self.assertIn(PUPPET_MODULE_1['name'], proc.stdout.split('\n'), proc)
Ejemplo n.º 41
0
    def make_user(self, cfg):
        """Create a user account with a home directory and an SSH keypair.

        In addition, schedule the user for deletion with ``self.addCleanup``.

        :param pulp_smash.config.ServerConfig cfg: Information about the server
            being targeted.
        :returns: A ``(username, private_key)`` tuple.
        """
        sudo = '' if utils.is_root(cfg) else 'sudo '
        creator = _make_user(cfg)
        username = next(creator)
        self.addCleanup(
            cli.Client(cfg).run,
            (sudo + 'userdel --remove {}').format(username).split()
        )
        private_key = next(creator)
        return (username, private_key)
Ejemplo n.º 42
0
 def setUpClass(cls):
     """Find a RPM with more than one version on repo1."""
     super(CopyAndPublishTwoVersionsRepoTestCase, cls).setUpClass()
     cls.client = cli.Client(cls.cfg)
     cls.sudo = '' if is_root(cls.cfg) else 'sudo '
     # Retrieve all modules with multiple versions in the repo1.
     rpms = {
         key: value
         for key, value in _get_rpm_names_versions(
             cls.cfg, _REPO_ID).items()
         if len(value) > 1
     }
     assert len(rpms) > 0
     # Choose a random module with multiple versions.
     cls.rpm_name = random.choice(list(rpms.keys()))
     versions = rpms[cls.rpm_name]
     versions.sort()
     cls.rpm_old_version = versions[-2]
     cls.rpm_new_version = versions[-1]
Ejemplo n.º 43
0
    def _create_repo_file(self, cfg, repo):
        """Create a file in ``/etc/yum.repos.d/`` referencing the repository.

        Also, schedule it for deletion. Return nothing.
        """
        verify = cfg.get_systems('api')[0].roles['api'].get('verify')
        sudo = () if utils.is_root(cfg) else ('sudo', )
        repo_path = gen_yum_config_file(
            cfg,
            baseurl=urljoin(
                cfg.get_base_url(),
                urljoin('pulp/repos/',
                        repo['distributors'][0]['config']['relative_url'])),
            enabled=1,
            gpgcheck=0,
            metadata_expire=0,  # force metadata to load every time
            repositoryid=repo['id'],
            sslverify='yes' if verify else 'no',
        )
        self.addCleanup(cli.Client(cfg).run, sudo + ('rm', repo_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)
Ejemplo n.º 45
0
    def _do_test(self, file_, label, recursive=False):
        """Assert that certain files have a label of ``label``.

        Get the SELinux label of the given ``file_``, or all files rooted at
        ``file_` if ``recursive`` is true. For each SELinux label, strip off
        the leading "user" portion of the label, and assert that the result — a
        string in the form :role:type:level — has the given ``label``.
        """
        # Typical output:
        #
        #     # getfattr --name=security.selinux /etc/passwd
        #     getfattr: Removing leading '/' from absolute path names
        #     # file: etc/passwd
        #     security.selinux="system_u:object_r:passwd_file_t:s0"
        #
        cmd = [] if utils.is_root(config.get_config()) else ['sudo']
        cmd.extend(('getfattr', '--name=security.selinux'))
        if recursive:
            cmd.append('--recursive')
        cmd.append(file_)
        lines = self.client.run(cmd).stdout.splitlines()
        matches = 0
        getfattr_file = None  # tracks file currently under consideration
        for line in lines:

            match = self.file_matcher.match(line)
            if match is not None:
                getfattr_file = match.groups(1)
                continue

            match = self.label_matcher.match(line)
            if match is not None:
                matches += 1
                # Strip "user" prefix from label. For example:
                # user:role:type:level → :role:type:level
                file_label = match.group(1)
                file_label = file_label[file_label.find(':'):]
                self.assertEqual(file_label, label, getfattr_file)

        self.assertGreater(matches, 0, lines)
Ejemplo n.º 46
0
    def _make_user(cfg):
        """Create a user account on a target system.

        This method is implemented as a generator. When executed, it will yield
        a username and private key. The corresponding public key is made the
        one and only key in the user's ``authorized_keys`` file.

        The username and private key are yielded one-by-one rather than as a
        pair because the user creation and key creation steps are executed
        serially.  Should the latter fail, the calling function will still be
        able to delete the created user.

        The user is given a home directory. When deleting this user, make sure
        to pass ``--remove`` to ``userdel``. Otherwise, the home directory will
        be left in place.
        """
        client = cli.Client(cfg)
        sudo = '' if utils.is_root(cfg) else 'sudo '

        # According to useradd(8), usernames may be up to 32 characters long.
        # But long names break the rsync publish process: (SNIP == username)
        #
        #     unix_listener:
        #     "/tmp/rsync_distributor-[SNIP]@example.com:22.64tcAiD8em417CiN"
        #     too long for Unix domain socket
        #
        username = utils.uuid4()[:12]
        cmd = 'useradd --create-home {0}'
        client.run((sudo + cmd.format(username)).split())
        yield username

        cmd = 'runuser --shell /bin/sh {} --command'.format(username)
        cmd = (sudo + cmd).split()
        cmd.append('ssh-keygen -N "" -f /home/{}/.ssh/mykey'.format(username))
        client.run(cmd)
        cmd = 'cp /home/{0}/.ssh/mykey.pub /home/{0}/.ssh/authorized_keys'
        client.run((sudo + cmd.format(username)).split())
        cmd = 'cat /home/{0}/.ssh/mykey'
        private_key = client.run((sudo + cmd.format(username)).split()).stdout
        yield private_key
Ejemplo n.º 47
0
def _make_user(cfg):
    """A generator to create a user account on the target system.

    Yield a username and private key. The corresponding public key is made the
    one and only key in the user's ``authorized_keys`` file.

    The username and private key are yielded one-by-one rather than as a pair
    because the user creation and key creation steps are executed serially.
    Should the latter fail, the calling function will still be able to delete
    the created user.

    The user is given a home directory. When deleting this user, make sure to
    pass ``--remove`` to ``userdel``. Otherwise, the home directory will be
    left in place.
    """
    client = cli.Client(cfg)
    sudo = '' if utils.is_root(cfg) else 'sudo '

    # According to useradd(8), usernames may be up to 32 characters long. But
    # long names break the rsync publish process: (SNIP == username)
    #
    #     unix_listener:
    #     "/tmp/rsync_distributor-[SNIP]@example.com:22.64tcAiD8em417CiN"
    #     too long for Unix domain socket
    #
    username = utils.uuid4()[:12]
    cmd = 'useradd --create-home {0}'
    client.run((sudo + cmd.format(username)).split())
    yield username

    cmd = 'runuser --shell /bin/sh {} --command'.format(username)
    cmd = (sudo + cmd).split()
    cmd.append('ssh-keygen -N "" -f /home/{}/.ssh/mykey'.format(username))
    client.run(cmd)
    cmd = 'cp /home/{0}/.ssh/mykey.pub /home/{0}/.ssh/authorized_keys'
    client.run((sudo + cmd.format(username)).split())
    cmd = 'cat /home/{0}/.ssh/mykey'
    private_key = client.run((sudo + cmd.format(username)).split()).stdout
    yield private_key
Ejemplo n.º 48
0
    def delete_user(cfg, username):
        """Delete a user.

        The Pulp rsync distributor has a habit of leaving (idle?) SSH sessions
        open even after publishing a repository. When executed, this function
        will:

        1. Poll the process list until all processes belonging to ``username``
           have died, or raise a ``unittest.SkipTest`` exception if the time
           limit is exceeded.
        2. Delete ``username``.
        """
        sudo = () if utils.is_root(cfg) else ('sudo', )
        client = cli.Client(cfg)

        # values are arbitrary
        iter_time = 2  # seconds
        iter_limit = 15  # unitless

        # Wait for user's processes to die.
        cmd = sudo + ('ps', '-wwo', 'args', '--user', username, '--no-headers')
        i = 0
        while i <= iter_limit:
            try:
                user_processes = client.run(cmd).stdout.splitlines()
            except exceptions.CalledProcessError:
                break
            i += 1
            time.sleep(iter_time)
        else:
            raise unittest.SkipTest(
                'User still has processes running after {}+ seconds. Aborting '
                'test. User processes: {}'.format(iter_time * iter_limit,
                                                  user_processes))

        # Delete user.
        cmd = sudo + ('userdel', '--remove', username)
        client.run(cmd)
Ejemplo n.º 49
0
    def do_test(self, distributor_config_update):
        """Implement most of the test logic."""
        rpms = tuple(
            utils.http_get(url)
            for url in (RPM_UNSIGNED_URL, RPM2_UNSIGNED_URL))

        # Create a repository.
        client = api.Client(self.cfg, api.json_handler)
        body = gen_repo()
        body['distributors'] = [gen_distributor()]
        body['distributors'][0]['distributor_config'].update(
            distributor_config_update)
        repo = client.post(REPOSITORY_PATH, body)
        self.addCleanup(client.delete, repo['_href'])
        repo = client.get(repo['_href'], params={'details': True})

        # Upload an RPM, publish the repo, and count metadata files twice.
        cli_client = cli.Client(self.cfg)
        sudo = () if utils.is_root(self.cfg) else ('sudo', )
        find_repodata_cmd = sudo + (
            'find',
            os.path.join('/var/lib/pulp/published/yum/master/yum_distributor/',
                         str(repo['id'])), '-type', 'd', '-name', 'repodata')
        found = []
        for rpm in rpms:
            utils.upload_import_unit(
                self.cfg,
                rpm,
                {'unit_type_id': 'rpm'},
                repo,
            )
            utils.publish_repo(self.cfg, repo)
            repodata_path = cli_client.run(find_repodata_cmd).stdout.strip()
            found.append(
                cli_client.run(sudo + ('find', repodata_path, '-type',
                                       'f')).stdout.splitlines())
        return found
    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)
Ejemplo n.º 51
0
 def test_true(self):
     """Assert the method returns ``True`` when root."""
     with mock.patch.object(cli, 'Client') as clien:
         clien.return_value.run.return_value.stdout.strip.return_value = '0'
         self.assertTrue(utils.is_root(None))
Ejemplo n.º 52
0
 def test_false(self):
     """Assert the method returns ``False`` when non-root."""
     with mock.patch.object(cli, 'Client') as clien:
         clien.return_value.run.return_value.stdout.strip.return_value = '1'
         self.assertFalse(utils.is_root(None))