def step_a_file_with_type_added_into_repository(ctx, filepath, mdtype, repository):
    """
    Example:

    Given repository "base" with packages
        | Package | Tag     | Value |
        | TestA   | Version | 1     |
    And a file "metadata.ini" with type "newmd" added into repository "base"
        \"\"\"
        [example]
        TestA = 1
        \"\"\"
    """
    # verify that modifyrepo_c is present
    modifyrepo = which("modifyrepo_c")
    ctx.assertion.assertIsNotNone(modifyrepo, "modifyrepo_c is required")

    repodir = repo_utils.get_repo_dir(repository)

    if not os.path.isfile(filepath):
        ctx.assertion.assertIsNotNone(ctx.text, "Multiline text is not provided")
        tmpdir = tempfile.mkdtemp()
        filepath = os.path.join(tmpdir, os.path.basename(filepath))
        with open(filepath, 'w') as fw:
            fw.write(ctx.text)

    file_utils.set_dir_content_ownership(ctx, repodir, 'root')   # change file ownership to root so we can change it
    cmd = "{} --mdtype={} {} {}".format(modifyrepo, mdtype, filepath, os.path.join(repodir, "repodata"))
    step_i_successfully_run_command(ctx, cmd)
    file_utils.set_dir_content_ownership(ctx, repodir)   # restore file ownership
def then_update_repository_with_packages(ctx, repository):
    """
    Examples:

       Feature: Working with repositories

         Given I update http repository base with packages
            | Package | Tag | Value |
            | foo     |     |       |

         Given I update http repository "updates" with packages
            | Package | Tag     | Value |
            | foo     | Version |  2.1  |
            | foo v3  | Version |  3.1  |

    """
    packages = table_utils.parse_skv_table(ctx, HEADINGS_REPO,
                                           PKG_TAGS, PKG_TAGS_REPEATING)

    rpmbuild = which("rpmbuild")
    ctx.assertion.assertIsNotNone(rpmbuild, "rpmbuild is required")
    createrepo = which("createrepo_c")
    ctx.assertion.assertIsNotNone(createrepo, "createrepo_c is required")

    repodir = repo_utils.get_repo_dir(repository)
    tmpdir = repodir
    srpm_tmpdir = '{}-source'.format(tmpdir.rstrip('/'))
    template = JINJA_ENV.from_string(PKG_TMPL)
    for name, settings in packages.items():
        name = name.split()[0]  # cut-off the pkg name _suffix_ to allow defining multiple package versions
        disttag = ""
        if '/' in name:  # using the module/pkgname notation, module would be placed to a disttag
            (module, name) = name.split('/', 1)
            disttag = ".{}".format(module)
        # before processing the template
        #   lower all characters
        #   replace '%' in Tag name with '_'
        #   replace '(' in Tag name with '_'
        #   delete all ')' in Tag
        settings = {k.lower().replace('%', '_').replace('(', '_').replace(')', ''): v for k, v in settings.items()}
        ctx.text = template.render(name=name, disttag=disttag, **settings)
        fname = "{!s}/{!s}.spec".format(tmpdir, name)
        step_a_file_filepath_with(ctx, fname)
        buildname = '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}.rpm'
        if 'arch' not in settings or settings['arch'] == 'noarch':
            cmd = "{!s} --define '_rpmdir {!s}' --define '_srcrpmdir {!s}' \
                   --define '_build_name_fmt {!s}' -ba {!s}" \
                   .format(rpmbuild, tmpdir, srpm_tmpdir, buildname, fname)
        else:
            cmd = "setarch {!s} {!s} --define '_rpmdir {!s}' --define '_srcrpmdir {!s}' \
                   --define '_build_name_fmt {!s}' --target {!s} -ba {!s}" \
                   .format(settings['arch'], rpmbuild, tmpdir, srpm_tmpdir, buildname, settings['arch'], fname)
        step_i_successfully_run_command(ctx, cmd)

    file_utils.set_dir_content_ownership(ctx, repodir, 'root')   # change file ownership to root so we can change it
    cmd = "{!s} --update {!s}".format(createrepo, repodir)
    step_i_successfully_run_command(ctx, cmd)
    file_utils.set_dir_content_ownership(ctx, repodir)   # restore file ownership
def set_dir_content_ownership(ctx, directory, user=None):
    if not user:
        if directory.startswith('/var/www/html'):
            user = '******'
        elif directory.startswith('/var/ftp'):
            user = '******'
        else:
            user = '******'
    cmd = 'chown -R {!s} {!s}'.format(user, directory)
    step_i_successfully_run_command(ctx, cmd)
def step_gpg_key_signed_by(ctx, signed_key, signing_key):
    """
    Signs one GPG with another GPG key producing a detached signature file.

    Examples:

    .. code-block:: gherkin

       Feature: GPG key signing

         Scenario: Sign one GPG with another
           Given GPG key "James Bond"
             And GPG key "M"
             And GPG key "James Bond" signed by "M"
    """
    signed_key_path = GPGKEY_FILEPATH_TMPL.format(signed_key, "pubkey")
    gpgbin = which("gpg2")
    cmd = "{!s} --detach-sig --armor --default-key '{!s}' '{!s}'".format(gpgbin, signing_key, signed_key_path)
    step_i_successfully_run_command(ctx, cmd)
Esempio n. 5
0
def step_gpg_key_signed_by(ctx, signed_key, signing_key):
    """
    Signs one GPG with another GPG key producing a detached signature file.

    Examples:

    .. code-block:: gherkin

       Feature: GPG key signing

         Scenario: Sign one GPG with another
           Given GPG key "James Bond"
             And GPG key "M"
             And GPG key "James Bond" signed by "M"
    """
    signed_key_path = GPGKEY_FILEPATH_TMPL.format(signed_key, "pubkey")
    gpgbin = which("gpg2")
    cmd = "{!s} --detach-sig --armor --default-key '{!s}' '{!s}'".format(
        gpgbin, signing_key, signed_key_path)
    step_i_successfully_run_command(ctx, cmd)
Esempio n. 6
0
def given_repository_metadata_signed_by(ctx, repository, gpgkey):
    """
    Signs repodata.xml for a given repository using the given GPG key and
    updates the repo file with gpgkey URL.
    Should be used after the repo is created or updated.

    .. note::

        The default dnf settings is *repo_gpgcheck = False*.

    Examples:

    .. code-block:: gherkin

       Feature: Repodata signatures

         Scenario: Setup repository with signed metadata
           Given GPG key "JamesBond"
             And GPG key "JamesBond" imported in rpm database
             And repository "TestRepo" with packages signed by "JamesBond"
               | Package | Tag | Value |
               | TestA   |     |       |
             And repository "TestRepo" metadata signed by "JamesBond"
             And a repo file of repository "TestRepo" modified with
               | Key           | Value |
               | repo_gpgcheck | True  |
    """
    # sign the repomd.xml file
    repodir = repo_utils.get_repo_dir(repository)
    gpg = which("gpg2")
    cmd = "{!s} --detach-sig --armor --default-key '{!s}' {!s}/repodata/repomd.xml".format(
        gpg, gpgkey, repodir)
    step_i_successfully_run_command(ctx, cmd)
    # update the repo file with path to the gpg key
    pubkey = GPGKEY_FILEPATH_TMPL.format(gpgkey, "pubkey")
    keyurl = "file://{!s}".format(pubkey)
    repofile = REPO_TMPL.format(repository)
    conf = file_utils.read_ini_file(repofile)
    conf.set(repository, "gpgkey", keyurl)
    file_utils.create_file_with_contents(repofile, conf)
def step_gpg_key_imported_in_rpm_database(ctx, name_real):
    """
    Imports the public key for the previously generated GPG key into the rpm database.

    Examples:

    .. code-block:: gherkin

       Feature: Package signatures

         Scenario: Setup repository with signed packages
           Given GPG key "James Bond"
             And GPG key "James Bond" imported in rpm database
             And repository "TestRepo" with packages signed by "James Bond"
               | Package | Tag | Value |
               | TestA   |     |       |

    """
    pubkey = GPGKEY_FILEPATH_TMPL.format(name_real, 'pubkey')
    rpm = which("rpm")
    cmd = "{!s} --import '{!s}'".format(rpm, pubkey)
    step_i_successfully_run_command(ctx, cmd)
Esempio n. 8
0
def step_gpg_key_imported_in_rpm_database(ctx, name_real):
    """
    Imports the public key for the previously generated GPG key into the rpm database.

    Examples:

    .. code-block:: gherkin

       Feature: Package signatures

         Scenario: Setup repository with signed packages
           Given GPG key "James Bond"
             And GPG key "James Bond" imported in rpm database
             And repository "TestRepo" with packages signed by "James Bond"
               | Package | Tag | Value |
               | TestA   |     |       |

    """
    pubkey = GPGKEY_FILEPATH_TMPL.format(name_real, 'pubkey')
    rpm = which("rpm")
    cmd = "{!s} --import '{!s}'".format(rpm, pubkey)
    step_i_successfully_run_command(ctx, cmd)
def given_repository_metadata_signed_by(ctx, repository, gpgkey):
    """
    Signs repodata.xml for a given repository using the given GPG key and
    updates the repo file with gpgkey URL.
    Should be used after the repo is created or updated.

    .. note::

        The default dnf settings is *repo_gpgcheck = False*.

    Examples:

    .. code-block:: gherkin

       Feature: Repodata signatures

         Scenario: Setup repository with signed metadata
           Given GPG key "JamesBond"
             And GPG key "JamesBond" imported in rpm database
             And repository "TestRepo" with packages signed by "JamesBond"
               | Package | Tag | Value |
               | TestA   |     |       |
             And repository "TestRepo" metadata signed by "JamesBond"
             And a repo file of repository "TestRepo" modified with
               | Key           | Value |
               | repo_gpgcheck | True  |
    """
    # sign the repomd.xml file
    repodir = repo_utils.get_repo_dir(repository)
    gpg = which("gpg2")
    cmd = "{!s} --detach-sig --armor --default-key '{!s}' {!s}/repodata/repomd.xml".format(gpg, gpgkey, repodir)
    step_i_successfully_run_command(ctx, cmd)
    # update the repo file with path to the gpg key
    pubkey = GPGKEY_FILEPATH_TMPL.format(gpgkey, "pubkey")
    keyurl = "file://{!s}".format(pubkey)
    repofile = REPO_TMPL.format(repository)
    conf = file_utils.read_ini_file(repofile)
    conf.set(repository, "gpgkey", keyurl)
    file_utils.create_file_with_contents(repofile, conf)
Esempio n. 10
0
def step_a_file_with_type_added_into_repository(ctx, filepath, mdtype,
                                                repository):
    """
    Example:

    Given repository "base" with packages
        | Package | Tag     | Value |
        | TestA   | Version | 1     |
    And a file "metadata.ini" with type "newmd" added into repository "base"
        \"\"\"
        [example]
        TestA = 1
        \"\"\"
    """
    # verify that modifyrepo_c is present
    modifyrepo = which("modifyrepo_c")
    ctx.assertion.assertIsNotNone(modifyrepo, "modifyrepo_c is required")

    repodir = repo_utils.get_repo_dir(repository)

    if not os.path.isfile(filepath):
        ctx.assertion.assertIsNotNone(ctx.text,
                                      "Multiline text is not provided")
        tmpdir = tempfile.mkdtemp()
        filepath = os.path.join(tmpdir, os.path.basename(filepath))
        with open(filepath, 'w') as fw:
            fw.write(ctx.text)

    file_utils.set_dir_content_ownership(
        ctx, repodir,
        'root')  # change file ownership to root so we can change it
    cmd = "{} --mdtype={} {} {}".format(modifyrepo, mdtype, filepath,
                                        os.path.join(repodir, "repodata"))
    step_i_successfully_run_command(ctx, cmd)
    file_utils.set_dir_content_ownership(ctx,
                                         repodir)  # restore file ownership
Esempio n. 11
0
def given_repository_with_packages(ctx,
                                   enabled,
                                   rtype,
                                   repository,
                                   gpgkey=None):
    """
    Builds dummy packages, creates repo and *.repo* file.
    Supported repo types are http, https, ftp or local (default).
    Supported architectures are x86_64, i686 and noarch (default).

    .. note::

       Along with the repository also *-source repository with
       src.rpm packages is built. The repository is disabled.

    .. note::

       *https* repositories are configured to use certificates at
       following locations:
         /etc/pki/tls/certs/testcerts/ca/cert.pem
         /etc/pki/tls/certs/testcerts/client/key.pem
         /etc/pki/tls/certs/testcerts/client/cert.pem

    .. note::

       Requires *rpmbuild* and *createrepo_c*.

    Requires table with following headers:

    ========= ===== =======
     Package   Tag   Value
    ========= ===== =======

    *Tag* is tag in RPM. Supported ones are:

    ================== ===============
         Tag            Default value 
    ================== ===============
    Summary            Empty          
    Version            1              
    Release            1              
    Arch               x86_64         
    License            Public Domain  
    BuildRequires      []             
    Requires           []             
    Recommends         []             
    Suggests           []             
    Supplements        []             
    Enhances           []             
    Requires(pretrans) []             
    Requires(pre)      []             
    Requires(post)     []             
    Requires(preun)    []             
    Obsoletes          []             
    Provides           []             
    Conflicts          []             
    %pretrans          Empty          
    %pre               Empty          
    %post              Empty          
    %preun             Empty          
    %postun            Empty          
    %posttrans         Empty          
    ================== ===============

    All packages are built during step execution.

    .. note::

        *BuildRequires* are ignored for build-time (*rpmbuild* is executed
        with ``--nodeps`` option).

        If there is a space character in the package name only the preceding
        part is used.

    .. note::

        Scriptlets such as *%pre* can be listed multiple time so that the
        entering of a multi-line script is more comfortable.

    Examples:

    .. code-block:: gherkin

       Feature: Working with repositories

         Background: Repository base with dummy package
               Given http repository base with packages
                  | Package | Tag | Value |
                  | foo     |     |       |

         Scenario: Installing dummy package from background
              When I enable repository base
              Then I successfully run "dnf -y install foo"

         Scenario: Creating repository with multiple package versions
             Given http repository "updates" with packages
                | Package | Tag     | Value |
                | foo     | Version |  2.0  |
                | foo v3  | Version |  3.0  |

         Scenario: Creating a package with %pre scriptlet failing
             Given http repository "more_updates" with packages
                | Package | Tag     | Value   |
                | foo     | Version |  4.0    |
                |         | %pre    |  exit 1 |
    """
    packages = table_utils.parse_skv_table(ctx, HEADINGS_REPO, PKG_TAGS,
                                           PKG_TAGS_REPEATING)

    rpmbuild = which("rpmbuild")
    ctx.assertion.assertIsNotNone(rpmbuild, "rpmbuild is required")
    createrepo = which("createrepo_c")
    ctx.assertion.assertIsNotNone(createrepo, "createrepo_c is required")

    if rtype == 'http' or rtype == 'https':
        tmpdir = tempfile.mkdtemp(dir='/var/www/html')
        repopath = os.path.join('localhost', os.path.basename(tmpdir))
    elif rtype == 'ftp':
        tmpdir = tempfile.mkdtemp(dir='/var/ftp/pub')
        repopath = os.path.join('localhost/pub', os.path.basename(tmpdir))
    else:
        tmpdir = tempfile.mkdtemp()
        repopath = tmpdir
    srpm_tmpdir = '{}-source'.format(tmpdir.rstrip('/'))
    srpm_repopath = '{}-source'.format(repopath.rstrip('/'))
    os.mkdir(srpm_tmpdir)  # create a directory for src.rpm pkgs
    template = JINJA_ENV.from_string(PKG_TMPL)
    for name, settings in packages.items():
        name = name.split(
        )[0]  # cut-off the pkg name _suffix_ to allow defining multiple package versions
        # before processing the template
        #   lower all characters
        #   replace '%' in Tag name with '_'
        #   replace '(' in Tag name with '_'
        #   delete all ')' in Tag
        settings = {
            k.lower().replace('%', '_').replace('(', '_').replace(')', ''): v
            for k, v in settings.items()
        }
        ctx.text = template.render(name=name, **settings)
        fname = "{!s}/{!s}.spec".format(tmpdir, name)
        step_a_file_filepath_with(ctx, fname)
        buildname = '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}.rpm'
        if 'arch' not in settings or settings['arch'] == 'noarch':
            cmd = "{!s} --define '_rpmdir {!s}' --define '_srcrpmdir {!s}' --define '_build_name_fmt {!s}' -ba {!s}".format(
                rpmbuild, tmpdir, srpm_tmpdir, buildname, fname)
        else:
            cmd = "setarch {!s} {!s} --define '_rpmdir {!s}' --define '_srcrpmdir {!s}' --define '_build_name_fmt {!s}' --target {!s} -ba {!s}".format(
                settings['arch'], rpmbuild, tmpdir, srpm_tmpdir, buildname,
                settings['arch'], fname)
        step_i_successfully_run_command(ctx, cmd)

    if gpgkey:
        # sign all rpms built
        rpmsign = which("rpmsign")
        rpms = glob.glob("{!s}/*.rpm".format(tmpdir))
        srpms = glob.glob("{!s}/*.rpm".format(srpm_tmpdir))
        cmd = "{!s} --addsign --key-id '{!s}' {!s} {!s}".format(
            rpmsign, gpgkey, ' '.join(rpms), ' '.join(srpms))
        step_i_successfully_run_command(ctx, cmd)

    cmd = "{!s} {!s}".format(createrepo, tmpdir)
    step_i_successfully_run_command(ctx, cmd)
    cmd = "{!s} {!s}".format(createrepo, srpm_tmpdir)
    step_i_successfully_run_command(ctx, cmd)

    # set proper directory content ownership
    file_utils.set_dir_content_ownership(ctx, tmpdir)
    file_utils.set_dir_content_ownership(ctx, srpm_tmpdir)

    repofile = REPO_TMPL.format(repository)
    ctx.table = Table(HEADINGS_INI)
    ctx.table.add_row([repository, "name", repository])
    ctx.table.add_row(["", "enabled", six.text_type(enabled)])
    ctx.table.add_row(["", "baseurl", "{!s}://{!s}".format(rtype, repopath)])
    if gpgkey:
        ctx.table.add_row(["", "gpgcheck", "True"])
    else:
        ctx.table.add_row(["", "gpgcheck", "False"])
    if rtype == 'https':
        ctx.table.add_row(
            ["", "sslcacert", "/etc/pki/tls/certs/testcerts/ca/cert.pem"])
        ctx.table.add_row([
            "", "sslclientkey", "/etc/pki/tls/certs/testcerts/client/key.pem"
        ])
        ctx.table.add_row([
            "", "sslclientcert", "/etc/pki/tls/certs/testcerts/client/cert.pem"
        ])
    step_an_ini_file_filepath_with(ctx, repofile)
    # create -source repository too
    srpm_repository = '{}-source'.format(repository)
    repofile = REPO_TMPL.format(srpm_repository)
    ctx.table = Table(HEADINGS_INI)
    ctx.table.add_row([srpm_repository, "name", srpm_repository])
    ctx.table.add_row(["", "enabled", "False"])
    ctx.table.add_row(
        ["", "baseurl", "{!s}://{!s}".format(rtype, srpm_repopath)])
    if gpgkey:
        ctx.table.add_row(["", "gpgcheck", "True"])
    else:
        ctx.table.add_row(["", "gpgcheck", "False"])
    if rtype == 'https':
        ctx.table.add_row(
            ["", "sslcacert", "/etc/pki/tls/certs/testcerts/ca/cert.pem"])
        ctx.table.add_row([
            "", "sslclientkey", "/etc/pki/tls/certs/testcerts/client/key.pem"
        ])
        ctx.table.add_row([
            "", "sslclientcert", "/etc/pki/tls/certs/testcerts/client/cert.pem"
        ])
    step_an_ini_file_filepath_with(ctx, repofile)
Esempio n. 12
0
def given_repository_with_packages(ctx, rtype, repository):
    """
    Builds dummy packages, creates repo and *.repo* file.
    Supported repo types are http, ftp or local (default).
    Supported architectures are x86_64, i686 and noarch (default).

    .. note::

       Requires *rpmbuild* and *createrepo_c*.

    Requires table with following headers:

    ========= ===== =======
     Package   Tag   Value
    ========= ===== =======

    *Tag* is tag in RPM. Supported ones are:

    ============= ===============
         Tag       Default value 
    ============= ===============
    Summary       Empty          
    Version       1              
    Release       1              
    Arch          x86_64         
    License       Public Domain  
    BuildRequires []             
    Requires      []             
    Obsoletes     []             
    Provides      []             
    Conflicts     []             
    ============= ===============

    All packages are built during step execution.

    .. note::

        *BuildRequires* are ignored for build-time (*rpmbuild* is executed
        with ``--nodeps`` option).

    Examples:

    .. code-block:: gherkin

       Feature: Working with repositories

         Background: Repository base with dummy package
               Given http repository base with packages
                  | Package | Tag | Value |
                  | foo     |     |       |

         Scenario: Installing dummy package from background
              When I enable repository base
              Then I successfully run "dnf -y install foo"
    """
    packages = table_utils.parse_skv_table(ctx, HEADINGS_REPO, PKG_TAGS,
                                           PKG_TAGS_REPEATING)

    rpmbuild = which("rpmbuild")
    ctx.assertion.assertIsNotNone(rpmbuild, "rpmbuild is required")
    createrepo = which("createrepo_c")
    ctx.assertion.assertIsNotNone(createrepo, "createrepo_c is required")

    if rtype == 'http':
        tmpdir = tempfile.mkdtemp(dir='/var/www/html')
        repopath = os.path.join('localhost', os.path.basename(tmpdir))
    elif rtype == 'ftp':
        tmpdir = tempfile.mkdtemp(dir='/var/ftp/pub')
        repopath = os.path.join('localhost/pub', os.path.basename(tmpdir))
    else:
        tmpdir = tempfile.mkdtemp()
        repopath = tmpdir
    template = JINJA_ENV.from_string(PKG_TMPL)
    for name, settings in packages.items():
        settings = {k.lower(): v for k, v in settings.items()}
        ctx.text = template.render(name=name, **settings)
        fname = "{!s}/{!s}.spec".format(tmpdir, name)
        step_a_file_filepath_with(ctx, fname)
        if 'arch' not in settings or settings['arch'] == 'noarch':
            cmd = "{!s} --define '_rpmdir {!s}' -bb {!s}".format(
                rpmbuild, tmpdir, fname)
        else:
            cmd = "setarch {!s} {!s} --define '_rpmdir {!s}' --target {!s} -bb {!s}".format(
                settings['arch'], rpmbuild, tmpdir, settings['arch'], fname)
        step_i_successfully_run_command(ctx, cmd)

    cmd = "{!s} {!s}".format(createrepo, tmpdir)
    step_i_successfully_run_command(ctx, cmd)

    # set proper directory content ownership
    file_utils.set_dir_content_ownership(ctx, tmpdir)

    repofile = REPO_TMPL.format(repository)
    ctx.table = Table(HEADINGS_INI)
    ctx.table.add_row([repository, "name", repository])
    ctx.table.add_row(["", "enabled", "False"])
    ctx.table.add_row(["", "gpgcheck", "False"])
    ctx.table.add_row(["", "baseurl", "{!s}://{!s}".format(rtype, repopath)])
    step_an_ini_file_filepath_with(ctx, repofile)
Esempio n. 13
0
def given_package_groups_defined_in_repository(ctx, repository):
    """
    For a given repository creates comps.xml file with described
    package groups and recreates the repo

    .. note::

       Requires *createrepo_c* and the repo to be already created.

    Requires table with following headers:

    ========= ===== =======
     Group     Tag   Value
    ========= ===== =======

    *Tag* is describing characteristics of the respective
    package group.Supported tags are:

    ============== ===============
         Tag        Default value 
    ============== ===============
    is_default          false     
    is_uservisible      true      
    description         ""        
    mandatory           []        
    default             []        
    optional            []        
    conditional         []        
    ============== ===============

    Examples:

    .. code-block:: gherkin

       Feature: Installing a package group

         @setup
         Scenario: Repository base with package group minimal
              Given repository "base" with packages
                 | Package | Tag | Value |
                 | foo     |     |       |
                 | bar     |     |       |
                 | baz     |     |       |
                 | qux     |     |       |
              And package groups defined in repository "base"
                 | Group    | Tag         | Value   |
                 | minimal  | mandatory   | foo     |
                 |          | default     | bar     |
                 |          | conditional | baz qux |

         Scenario: Installing package group from background
              When I enable repository "base"
              Then I successfully run "dnf -y group install minimal"

    .. note::

       Conditional packages are described in a form PKG REQUIREDPKG

    """
    HEADINGS_GROUP = ['Group', 'Tag', 'Value']
    GROUP_TAGS_REPEATING = ['mandatory', 'default', 'optional', 'conditional']
    GROUP_TAGS = ['is_default', 'is_uservisible', 'description'] + GROUP_TAGS_REPEATING
    pkg_groups = table_utils.parse_skv_table(ctx, HEADINGS_GROUP, GROUP_TAGS, GROUP_TAGS_REPEATING)

    createrepo = which("createrepo_c")
    ctx.assertion.assertIsNotNone(createrepo, "createrepo_c is required")

    # prepare the comps.xml
    comps_xml = COMPS_PREFIX
    template = JINJA_ENV.from_string(COMPS_TMPL)
    for name, settings in pkg_groups.items():
        settings = {k.lower(): v for k, v in settings.items()}
        comps_xml += template.render(name=name, **settings)
    comps_xml += COMPS_SUFFIX

    # save comps.xml and recreate the repo
    repodir = repo_utils.get_repo_dir(repository)
    with open(os.path.join(repodir, "comps.xml"), "w") as f_comps:
        f_comps.write(comps_xml)
    file_utils.set_dir_content_ownership(ctx, repodir, 'root')   # change file ownership to root so we can change it
    cmd = "{!s} -g comps.xml --update {!s}".format(createrepo, repodir)
    step_i_successfully_run_command(ctx, cmd)
    file_utils.set_dir_content_ownership(ctx, repodir)   # restore file ownership
Esempio n. 14
0
def step_updateinfo_defined_in_repository(ctx, repository):
    """
    For a given repository creates updateinfo.xml file with described
    updates and recreates the repo

    .. note::

       Requires *modifyrepo_c* and the repo to be already created.

    Requires table with following headers:

    ==== ===== =======
     Id   Tag   Value
    ==== ===== =======

    *Tag* is describing attributes of the respective update.
    Supported tags are:

    ============ =========================
         Tag      Default value
    ============ =========================
    Title        Default title of Id
    Type         security
    Description  Default description of Id
    Summary      Default summary of Id
    Severity     Low
    Solution     Default solution of Id
    Rights       nobody
    Issued       2017-01-01 00:00:01
    Updated      2017-01-01 00:00:01
    Reference    none
    Package      none
    ============ =========================

    Examples:

    .. code-block:: gherkin

       Feature: Defining updateinfo in a repository

         @setup
         Scenario: Repository base with updateinfo defined
              Given repository "base" with packages
                 | Package | Tag     | Value |
                 | foo     | Version | 2     |
                 | bar     | Version | 2     |
              And updateinfo defined in repository "base"
                 | Id            | Tag         | Value                     |
                 | RHSA-2017-001 | Title       | foo bar security update   |
                 |               | Type        | security                  |
                 |               | Description | Fixes buffer overflow     |
                 |               | Summary     | Critical bug is fixed     |
                 |               | Severity    | Critical                  |
                 |               | Solution    | Update to the new version |
                 |               | Rights      | Copyright 2017 Baz Inc    |
                 |               | Reference   | CVE-2017-0001             |
                 |               | Reference   | BZ123456                  |
                 |               | Package     | foo-2                     |
                 |               | Package     | bar-2                     |

    .. note::

       Specifying Version or Release in Package tag is not necessary, however
       when multiple RPMs matches the string the last one from the sorted
       list is used.
    """
    HEADINGS_GROUP = ['Id', 'Tag', 'Value']
    UPDATEINFO_TAGS_REPEATING = ['Package', 'Reference']
    UPDATEINFO_TAGS = ['Title', 'Type', 'Description', 'Solution', 'Summary', 'Severity', 'Rights', 'Issued', 'Updated'] + \
                      UPDATEINFO_TAGS_REPEATING
    updateinfo_table = table_utils.parse_skv_table(ctx, HEADINGS_GROUP, UPDATEINFO_TAGS, UPDATEINFO_TAGS_REPEATING)

    # verify that modifyrepo_c is present
    modifyrepo = which("modifyrepo_c")
    ctx.assertion.assertIsNotNone(modifyrepo, "modifyrepo_c is required")

    # prepare updateinfo.xml content
    repodir = repo_utils.get_repo_dir(repository)
    updateinfo_xml = repo_utils.get_updateinfo_xml(repository, updateinfo_table)

    # save it to the updateinfo.xml file and recreate the repodata
    tmpdir = tempfile.mkdtemp()
    with open(os.path.join(tmpdir, "updateinfo.xml"), 'w') as fw:
        fw.write(updateinfo_xml)
    file_utils.set_dir_content_ownership(ctx, repodir, 'root')   # change file ownership to root so we can change it
    cmd = "{!s} {!s} {!s}".format(modifyrepo, os.path.join(tmpdir, 'updateinfo.xml'), os.path.join(repodir, 'repodata'))
    step_i_successfully_run_command(ctx, cmd)
    file_utils.set_dir_content_ownership(ctx, repodir)   # restore file ownership
Esempio n. 15
0
def given_repository_with_packages(ctx, rtype, repository, gpgkey=None):
    """
    Builds dummy packages, creates repo and *.repo* file.
    Supported repo types are http, https, ftp or local (default).
    Supported architectures are x86_64, i686 and noarch (default).

    .. note::

       *https* repositories are configured to use certificates at
       following locations:
         /etc/pki/tls/certs/testcerts/ca/cert.pem
         /etc/pki/tls/certs/testcerts/client/key.pem
         /etc/pki/tls/certs/testcerts/client/cert.pem

    .. note::

       Requires *rpmbuild* and *createrepo_c*.

    Requires table with following headers:

    ========= ===== =======
     Package   Tag   Value
    ========= ===== =======

    *Tag* is tag in RPM. Supported ones are:

    ============= ===============
         Tag       Default value 
    ============= ===============
    Summary       Empty          
    Version       1              
    Release       1              
    Arch          x86_64         
    License       Public Domain  
    BuildRequires []             
    Requires      []             
    Obsoletes     []             
    Provides      []             
    Conflicts     []             
    ============= ===============

    All packages are built during step execution.

    .. note::

        *BuildRequires* are ignored for build-time (*rpmbuild* is executed
        with ``--nodeps`` option).

    Examples:

    .. code-block:: gherkin

       Feature: Working with repositories

         Background: Repository base with dummy package
               Given http repository base with packages
                  | Package | Tag | Value |
                  | foo     |     |       |

         Scenario: Installing dummy package from background
              When I enable repository base
              Then I successfully run "dnf -y install foo"
    """
    packages = table_utils.parse_skv_table(ctx, HEADINGS_REPO,
                                           PKG_TAGS, PKG_TAGS_REPEATING)

    rpmbuild = which("rpmbuild")
    ctx.assertion.assertIsNotNone(rpmbuild, "rpmbuild is required")
    createrepo = which("createrepo_c")
    ctx.assertion.assertIsNotNone(createrepo, "createrepo_c is required")

    if rtype == 'http' or rtype == 'https':
        tmpdir = tempfile.mkdtemp(dir='/var/www/html')
        repopath = os.path.join('localhost', os.path.basename(tmpdir))
    elif rtype == 'ftp':
        tmpdir = tempfile.mkdtemp(dir='/var/ftp/pub')
        repopath = os.path.join('localhost/pub', os.path.basename(tmpdir))
    else:
        tmpdir = tempfile.mkdtemp()
        repopath = tmpdir
    template = JINJA_ENV.from_string(PKG_TMPL)
    for name, settings in packages.items():
        settings = {k.lower(): v for k, v in settings.items()}
        ctx.text = template.render(name=name, **settings)
        fname = "{!s}/{!s}.spec".format(tmpdir, name)
        step_a_file_filepath_with(ctx, fname)
        buildname = '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}.rpm'
        if 'arch' not in settings or settings['arch'] == 'noarch':
            cmd = "{!s} --define '_rpmdir {!s}' --define '_build_name_fmt {!s}' -bb {!s}".format(
                rpmbuild, tmpdir, buildname, fname)
        else:
            cmd = "setarch {!s} {!s} --define '_rpmdir {!s}' --define '_build_name_fmt {!s}' --target {!s} -bb {!s}".format(
                settings['arch'], rpmbuild, tmpdir, buildname, settings['arch'], fname)
        step_i_successfully_run_command(ctx, cmd)

    if gpgkey:
        # sign all rpms built
        rpmsign = which("rpmsign")
        rpms = glob.glob("{!s}/*.rpm".format(tmpdir))
        cmd = "{!s} --addsign --key-id '{!s}' {!s}".format(rpmsign, gpgkey, ' '.join(rpms))
        step_i_successfully_run_command(ctx, cmd)

    cmd = "{!s} {!s}".format(createrepo, tmpdir)
    step_i_successfully_run_command(ctx, cmd)

    # set proper directory content ownership
    file_utils.set_dir_content_ownership(ctx, tmpdir)

    repofile = REPO_TMPL.format(repository)
    ctx.table = Table(HEADINGS_INI)
    ctx.table.add_row([repository, "name",     repository])
    ctx.table.add_row(["",         "enabled",  "False"])
    ctx.table.add_row(["",         "baseurl",  "{!s}://{!s}".format(rtype, repopath)])
    if gpgkey:
        ctx.table.add_row(["", "gpgcheck", "True"])
    else:
        ctx.table.add_row(["", "gpgcheck", "False"])
    if rtype == 'https':
        ctx.table.add_row(["", "sslcacert",     "/etc/pki/tls/certs/testcerts/ca/cert.pem"])
        ctx.table.add_row(["", "sslclientkey",  "/etc/pki/tls/certs/testcerts/client/key.pem"])
        ctx.table.add_row(["", "sslclientcert", "/etc/pki/tls/certs/testcerts/client/cert.pem"])
    step_an_ini_file_filepath_with(ctx, repofile)
Esempio n. 16
0
def given_repository_with_packages(ctx, repository):
    """
    Builds dummy noarch packages, creates repo and *.repo* file.

    .. note::

       Requires *rpmbuild* and *createrepo_c*.

    Requires table with following headers:

    ========= ===== =======
     Package   Tag   Value
    ========= ===== =======

    *Tag* is tag in RPM. Supported ones are:

    ============= ===============
         Tag       Default value 
    ============= ===============
    Summary       Empty          
    Version       1              
    Release       1              
    License       Public Domain  
    BuildRequires []             
    Requires      []             
    Obsoletes     []             
    Provides      []             
    ============= ===============

    All packages are built during step execution.

    .. note::

        *BuildRequires* are ignored for build-time (*rpmbuild* is executed
        with ``--nodeps`` option).

    Examples:

    .. code-block:: gherkin

       Feature: Working with repositories

         Background: Repository base with dummy package
               Given repository base with packages
                  | Package | Tag | Value |
                  | foo     |     |       |

         Scenario: Installing dummy package from background
              When I enable repository base
              Then I successfully run "dnf -y install foo"
    """
    packages = table_utils.parse_skv_table(ctx, HEADINGS_REPO, PKG_TAGS,
                                           PKG_TAGS_REPEATING)

    rpmbuild = which("rpmbuild")
    ctx.assertion.assertIsNotNone(rpmbuild, "rpmbuild is required")
    createrepo = which("createrepo_c")
    ctx.assertion.assertIsNotNone(createrepo, "createrepo_c is required")

    tmpdir = tempfile.mkdtemp()
    template = JINJA_ENV.from_string(PKG_TMPL)
    for name, settings in packages.items():
        settings = {k.lower(): v for k, v in settings.items()}
        ctx.text = template.render(name=name, **settings)
        fname = "{!s}/{!s}.spec".format(tmpdir, name)
        step_a_file_filepath_with(ctx, fname)
        cmd = "{!s} --define '_rpmdir {!s}' -bb {!s}".format(
            rpmbuild, tmpdir, fname)
        step_i_successfully_run_command(ctx, cmd)
    cmd = "{!s} {!s}".format(createrepo, tmpdir)
    step_i_successfully_run_command(ctx, cmd)

    repofile = REPO_TMPL.format(repository)
    ctx.table = Table(HEADINGS_INI)
    ctx.table.add_row([repository, "name", repository])
    ctx.table.add_row(["", "enabled", "False"])
    ctx.table.add_row(["", "gpgcheck", "False"])
    ctx.table.add_row(["", "baseurl", "file://{!s}".format(tmpdir)])
    step_an_ini_file_filepath_with(ctx, repofile)
def given_repository_with_packages(ctx, enabled, rtype, repository, gpgkey=None):
    """
    Builds dummy packages, creates repo and *.repo* file.
    Supported repo types are http, https, ftp or local (default).
    Supported architectures are x86_64, i686 and noarch (default).

    .. note::

       Along with the repository also *-source repository with
       src.rpm packages is built. The repository is disabled.

    .. note::

       *https* repositories are configured to use certificates at
       following locations:
         /etc/pki/tls/certs/testcerts/ca/cert.pem
         /etc/pki/tls/certs/testcerts/client/key.pem
         /etc/pki/tls/certs/testcerts/client/cert.pem

    .. note::

       Requires *rpmbuild* and *createrepo_c*.

    Requires table with following headers:

    ========= ===== =======
     Package   Tag   Value
    ========= ===== =======

    *Tag* is tag in RPM. Supported ones are:

    ================== ===============
         Tag            Default value 
    ================== ===============
    Summary            Empty          
    Version            1              
    Release            1              
    Arch               x86_64         
    License            Public Domain  
    BuildRequires      []             
    Requires           []             
    Recommends         []             
    Suggests           []             
    Supplements        []             
    Enhances           []             
    Requires(pretrans) []             
    Requires(pre)      []             
    Requires(post)     []             
    Requires(preun)    []             
    Obsoletes          []             
    Provides           []             
    Conflicts          []             
    %pretrans          Empty          
    %pre               Empty          
    %post              Empty          
    %preun             Empty          
    %postun            Empty          
    %posttrans         Empty          
    ================== ===============

    All packages are built during step execution.

    .. note::

        *BuildRequires* are ignored for build-time (*rpmbuild* is executed
        with ``--nodeps`` option).

        If there is a space character in the package name only the preceding
        part is used.

    .. note::

        Scriptlets such as *%pre* can be listed multiple time so that the
        entering of a multi-line script is more comfortable.

    Examples:

    .. code-block:: gherkin

       Feature: Working with repositories

         Background: Repository base with dummy package
               Given http repository base with packages
                  | Package | Tag | Value |
                  | foo     |     |       |

         Scenario: Installing dummy package from background
              When I enable repository base
              Then I successfully run "dnf -y install foo"

         Scenario: Creating repository with multiple package versions
             Given http repository "updates" with packages
                | Package | Tag     | Value |
                | foo     | Version |  2.0  |
                | foo v3  | Version |  3.0  |

         Scenario: Creating a package with %pre scriptlet failing
             Given http repository "more_updates" with packages
                | Package | Tag     | Value   |
                | foo     | Version |  4.0    |
                |         | %pre    |  exit 1 |
    """
    packages = table_utils.parse_skv_table(ctx, HEADINGS_REPO,
                                           PKG_TAGS, PKG_TAGS_REPEATING)

    rpmbuild = which("rpmbuild")
    ctx.assertion.assertIsNotNone(rpmbuild, "rpmbuild is required")
    createrepo = which("createrepo_c")
    ctx.assertion.assertIsNotNone(createrepo, "createrepo_c is required")

    if rtype == 'http' or rtype == 'https':
        tmpdir = tempfile.mkdtemp(dir='/var/www/html')
        repopath = os.path.join('localhost', os.path.basename(tmpdir))
    elif rtype == 'ftp':
        tmpdir = tempfile.mkdtemp(dir='/var/ftp/pub')
        repopath = os.path.join('localhost/pub', os.path.basename(tmpdir))
    else:
        tmpdir = tempfile.mkdtemp()
        repopath = tmpdir
    srpm_tmpdir = '{}-source'.format(tmpdir.rstrip('/'))
    srpm_repopath = '{}-source'.format(repopath.rstrip('/'))
    os.mkdir(srpm_tmpdir)  # create a directory for src.rpm pkgs
    template = JINJA_ENV.from_string(PKG_TMPL)
    for name, settings in packages.items():
        name = name.split()[0]  # cut-off the pkg name _suffix_ to allow defining multiple package versions
        disttag = ""
        if '/' in name:  # using the module/pkgname notation, module would be placed to a disttag
            (module, name) = name.split('/', 1)
            disttag = ".{}".format(module)
        # before processing the template
        #   lower all characters
        #   replace '%' in Tag name with '_'
        #   replace '(' in Tag name with '_'
        #   delete all ')' in Tag
        settings = {k.lower().replace('%', '_').replace('(', '_').replace(')', ''): v for k, v in settings.items()}
        ctx.text = template.render(name=name, disttag=disttag, **settings)
        fname = "{!s}/{!s}.spec".format(tmpdir, name)
        step_a_file_filepath_with(ctx, fname)
        buildname = '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}.rpm'
        if 'arch' not in settings or settings['arch'] == 'noarch':
            cmd = "{!s} --define '_rpmdir {!s}' --define '_srcrpmdir {!s}' --define '_build_name_fmt {!s}' -ba {!s}".format(
                rpmbuild, tmpdir, srpm_tmpdir, buildname, fname)
        else:
            cmd = "setarch {!s} {!s} --define '_rpmdir {!s}' --define '_srcrpmdir {!s}' --define '_build_name_fmt {!s}' --target {!s} -ba {!s}".format(
                settings['arch'], rpmbuild, tmpdir, srpm_tmpdir, buildname, settings['arch'], fname)
        step_i_successfully_run_command(ctx, cmd)

    if gpgkey:
        # sign all rpms built
        rpmsign = which("rpmsign")
        rpms = glob.glob("{!s}/*.rpm".format(tmpdir))
        srpms = glob.glob("{!s}/*.rpm".format(srpm_tmpdir))
        cmd = "{!s} --addsign --key-id '{!s}' {!s} {!s}".format(rpmsign, gpgkey, ' '.join(rpms), ' '.join(srpms))
        step_i_successfully_run_command(ctx, cmd)

    cmd = "{!s} {!s}".format(createrepo, tmpdir)
    step_i_successfully_run_command(ctx, cmd)
    cmd = "{!s} {!s}".format(createrepo, srpm_tmpdir)
    step_i_successfully_run_command(ctx, cmd)

    # set proper directory content ownership
    file_utils.set_dir_content_ownership(ctx, tmpdir)
    file_utils.set_dir_content_ownership(ctx, srpm_tmpdir)

    repofile = REPO_TMPL.format(repository)
    ctx.table = Table(HEADINGS_INI)
    ctx.table.add_row([repository, "name",          repository])
    ctx.table.add_row(["",         "enabled",       six.text_type(enabled)])
    ctx.table.add_row(["",         "baseurl",       "{!s}://{!s}".format(rtype, repopath)])
    if gpgkey:
        ctx.table.add_row(["",     "gpgcheck",      "True"])
    else:
        ctx.table.add_row(["",     "gpgcheck",      "False"])
    if rtype == 'https':
        ctx.table.add_row(["",     "sslcacert",     "/etc/pki/tls/certs/testcerts/ca/cert.pem"])
        ctx.table.add_row(["",     "sslclientkey",  "/etc/pki/tls/certs/testcerts/client/key.pem"])
        ctx.table.add_row(["",     "sslclientcert", "/etc/pki/tls/certs/testcerts/client/cert.pem"])
    step_an_ini_file_filepath_with(ctx, repofile)
    # create -source repository too
    srpm_repository = '{}-source'.format(repository)
    repofile = REPO_TMPL.format(srpm_repository)
    ctx.table = Table(HEADINGS_INI)
    ctx.table.add_row([srpm_repository, "name",          srpm_repository])
    ctx.table.add_row(["",              "enabled",       "False"])
    ctx.table.add_row(["",              "baseurl",       "{!s}://{!s}".format(rtype, srpm_repopath)])
    if gpgkey:
        ctx.table.add_row(["",          "gpgcheck",      "True"])
    else:
        ctx.table.add_row(["",          "gpgcheck",      "False"])
    if rtype == 'https':
        ctx.table.add_row(["",          "sslcacert",     "/etc/pki/tls/certs/testcerts/ca/cert.pem"])
        ctx.table.add_row(["",          "sslclientkey",  "/etc/pki/tls/certs/testcerts/client/key.pem"])
        ctx.table.add_row(["",          "sslclientcert", "/etc/pki/tls/certs/testcerts/client/cert.pem"])
    step_an_ini_file_filepath_with(ctx, repofile)
Esempio n. 18
0
def step_gpg_key(ctx, name_real):
    """
    Generates for the root user GPG key with a given identity,
    a.k.a. the Name-Real attribute.

    GPG key attributes can be optionally specified using the table with
    following headers:

    ======= =========
      Tag     Value  
    ======= =========

    Supported GPG key attrubutes are:

    ============= ===============
        Tag       Default value  
    ============= ===============
    Key-Type      RSA            
    Key-Length    2048           
    Subkey-Type   <not present>  
    Subkey-Length <not present>  
    Name-Comment  No Comment     
    Name-Email    dnf@noreply    
    Expire-Date   0              
    =============================

    .. note::
       GPG key configuration is saved in a file /root/${Name-Real}.keyconf
       respective public key is exported to a file /root/${Name-Real}.pubkey

    Examples:

    .. code-block:: gherkin

       Feature: Package signatures

         Scenario: Setup repository with signed packages
           Given GPG key "James Bond"
             And GPG key "James Bond" imported in rpm database
             And repository "TestRepo" with packages signed by "James Bond"
               | Package | Tag | Value |
               | TestA   |     |       |
    """

    if ctx.table:  # additional GPG key configuration listed in the table
        GPGKEY_HEADINGS = ['Tag', 'Value']
        GPGKEY_TAGS = [
            'Key-Type', 'Key-Length', 'Subkey-Type', 'Subkey-Length',
            'Name-Comment', 'Name-Email', 'Expire-Date'
        ]
        gpgkey_conf_table = table_utils.parse_kv_table(ctx, GPGKEY_HEADINGS,
                                                       GPGKEY_TAGS)
    else:  # no table present
        gpgkey_conf_table = {}
    template = JINJA_ENV.from_string(GPGKEY_CONF_TMPL)
    settings = {
        k.lower().replace('-', '_'): v
        for k, v in gpgkey_conf_table.items()
    }
    gpgkey_conf = template.render(name_real=name_real, **settings)
    # write gpgkey configuration to a file
    fpath = GPGKEY_FILEPATH_TMPL.format(name_real, "keyconf")
    with open(fpath, 'w') as fw:
        fw.write(gpgkey_conf)
    # generate the GPG key
    gpgbin = which("gpg2")
    cmd = "{!s} --batch --gen-key '{!s}'".format(gpgbin, fpath)
    step_i_successfully_run_command(ctx, cmd)
    # export the public key
    cmd = "{!s} --export --armor '{!s}'".format(gpgbin, name_real)
    step_i_successfully_run_command(ctx, cmd)
    fpath = GPGKEY_FILEPATH_TMPL.format(name_real, "pubkey")
    with open(fpath, 'w') as fw:
        fw.write(ctx.cmd_result.stdout)
Esempio n. 19
0
def step_updateinfo_defined_in_repository(ctx, repository):
    """
    For a given repository creates updateinfo.xml file with described
    updates and recreates the repo

    .. note::

       Requires *modifyrepo_c* and the repo to be already created.

    Requires table with following headers:

    ==== ===== =======
     Id   Tag   Value
    ==== ===== =======

    *Tag* is describing attributes of the respective update.
    Supported tags are:

    ============ =========================
         Tag      Default value
    ============ =========================
    Title        Default title of Id
    Type         security
    Description  Default description of Id
    Summary      Default summary of Id
    Severity     Low
    Solution     Default solution of Id
    Rights       nobody
    Issued       2017-01-01 00:00:01
    Updated      2017-01-01 00:00:01
    Reference    none
    Package      none
    ============ =========================

    Examples:

    .. code-block:: gherkin

       Feature: Defining updateinfo in a repository

         @setup
         Scenario: Repository base with updateinfo defined
              Given repository "base" with packages
                 | Package | Tag     | Value |
                 | foo     | Version | 2     |
                 | bar     | Version | 2     |
              And updateinfo defined in repository "base"
                 | Id            | Tag         | Value                     |
                 | RHSA-2017-001 | Title       | foo bar security update   |
                 |               | Type        | security                  |
                 |               | Description | Fixes buffer overflow     |
                 |               | Summary     | Critical bug is fixed     |
                 |               | Severity    | Critical                  |
                 |               | Solution    | Update to the new version |
                 |               | Rights      | Copyright 2017 Baz Inc    |
                 |               | Reference   | CVE-2017-0001             |
                 |               | Reference   | BZ123456                  |
                 |               | Package     | foo-2                     |
                 |               | Package     | bar-2                     |

    .. note::

       Specifying Version or Release in Package tag is not necessary, however
       when multiple RPMs matches the string the last one from the sorted
       list is used.
    """
    HEADINGS_GROUP = ['Id', 'Tag', 'Value']
    UPDATEINFO_TAGS_REPEATING = ['Package', 'Reference']
    UPDATEINFO_TAGS = ['Title', 'Type', 'Description', 'Solution', 'Summary', 'Severity', 'Rights', 'Issued', 'Updated'] + \
                      UPDATEINFO_TAGS_REPEATING
    updateinfo_table = table_utils.parse_skv_table(ctx, HEADINGS_GROUP,
                                                   UPDATEINFO_TAGS,
                                                   UPDATEINFO_TAGS_REPEATING)

    # verify that modifyrepo_c is present
    modifyrepo = which("modifyrepo_c")
    ctx.assertion.assertIsNotNone(modifyrepo, "modifyrepo_c is required")

    # prepare updateinfo.xml content
    repodir = repo_utils.get_repo_dir(repository)
    updateinfo_xml = repo_utils.get_updateinfo_xml(repository,
                                                   updateinfo_table)

    # save it to the updateinfo.xml file and recreate the repodata
    tmpdir = tempfile.mkdtemp()
    with open(os.path.join(tmpdir, "updateinfo.xml"), 'w') as fw:
        fw.write(updateinfo_xml)
    file_utils.set_dir_content_ownership(
        ctx, repodir,
        'root')  # change file ownership to root so we can change it
    cmd = "{!s} {!s} {!s}".format(modifyrepo,
                                  os.path.join(tmpdir, 'updateinfo.xml'),
                                  os.path.join(repodir, 'repodata'))
    step_i_successfully_run_command(ctx, cmd)
    file_utils.set_dir_content_ownership(ctx,
                                         repodir)  # restore file ownership
Esempio n. 20
0
def given_package_groups_defined_in_repository(ctx, repository):
    """
    For a given repository creates comps.xml file with described
    package groups and recreates the repo

    .. note::

       Requires *createrepo_c* and the repo to be already created.

    Requires table with following headers:

    ========= ===== =======
     Group     Tag   Value
    ========= ===== =======

    *Tag* is describing characteristics of the respective
    package group.Supported tags are:

    ============== ===============
         Tag        Default value 
    ============== ===============
    is_default          false     
    is_uservisible      true      
    description         ""        
    mandatory           []        
    default             []        
    optional            []        
    conditional         []        
    ============== ===============

    Examples:

    .. code-block:: gherkin

       Feature: Installing a package group

         @setup
         Scenario: Repository base with package group minimal
              Given repository "base" with packages
                 | Package | Tag | Value |
                 | foo     |     |       |
                 | bar     |     |       |
                 | baz     |     |       |
                 | qux     |     |       |
              And package groups defined in repository "base"
                 | Group    | Tag         | Value   |
                 | minimal  | mandatory   | foo     |
                 |          | default     | bar     |
                 |          | conditional | baz qux |

         Scenario: Installing package group from background
              When I enable repository "base"
              Then I successfully run "dnf -y group install minimal"

    .. note::

       Conditional packages are described in a form PKG REQUIREDPKG

    """
    HEADINGS_GROUP = ['Group', 'Tag', 'Value']
    GROUP_TAGS_REPEATING = ['mandatory', 'default', 'optional', 'conditional']
    GROUP_TAGS = ['is_default', 'is_uservisible', 'description'
                  ] + GROUP_TAGS_REPEATING
    pkg_groups = table_utils.parse_skv_table(ctx, HEADINGS_GROUP, GROUP_TAGS,
                                             GROUP_TAGS_REPEATING)

    createrepo = which("createrepo_c")
    ctx.assertion.assertIsNotNone(createrepo, "createrepo_c is required")
    createrepo = "{!s} {!s}".format(createrepo, "--no-database")

    # prepare the comps.xml
    comps_xml = COMPS_PREFIX
    template = JINJA_ENV.from_string(COMPS_TMPL)
    for name, settings in pkg_groups.items():
        settings = {k.lower(): v for k, v in settings.items()}
        comps_xml += template.render(name=name, **settings)
    comps_xml += COMPS_SUFFIX

    # save comps.xml and recreate the repo
    repodir = repo_utils.get_repo_dir(repository)
    with open(os.path.join(repodir, "comps.xml"), "w") as f_comps:
        f_comps.write(comps_xml)
    file_utils.set_dir_content_ownership(
        ctx, repodir,
        'root')  # change file ownership to root so we can change it
    cmd = "{!s} -g comps.xml --update {!s}".format(createrepo, repodir)
    step_i_successfully_run_command(ctx, cmd)
    file_utils.set_dir_content_ownership(ctx,
                                         repodir)  # restore file ownership
Esempio n. 21
0
def given_repository_with_packages(ctx, repository):
    """
    Builds dummy noarch packages, creates repo and *.repo* file.

    .. note::

       Requires *rpmbuild* and *createrepo_c*.

    Requires table with following headers:

    ========= ===== =======
     Package   Tag   Value
    ========= ===== =======

    *Tag* is tag in RPM. Supported ones are:

    ============= ===============
         Tag       Default value 
    ============= ===============
    Summary       Empty          
    Version       1              
    Release       1              
    License       Public Domain  
    BuildRequires []             
    Requires      []             
    Obsoletes     []             
    Provides      []             
    Conflicts     []             
    ============= ===============

    All packages are built during step execution.

    .. note::

        *BuildRequires* are ignored for build-time (*rpmbuild* is executed
        with ``--nodeps`` option).

    Examples:

    .. code-block:: gherkin

       Feature: Working with repositories

         Background: Repository base with dummy package
               Given repository base with packages
                  | Package | Tag | Value |
                  | foo     |     |       |

         Scenario: Installing dummy package from background
              When I enable repository base
              Then I successfully run "dnf -y install foo"
    """
    packages = table_utils.parse_skv_table(ctx, HEADINGS_REPO,
                                           PKG_TAGS, PKG_TAGS_REPEATING)

    rpmbuild = which("rpmbuild")
    ctx.assertion.assertIsNotNone(rpmbuild, "rpmbuild is required")
    createrepo = which("createrepo_c")
    ctx.assertion.assertIsNotNone(createrepo, "createrepo_c is required")

    tmpdir = tempfile.mkdtemp()
    template = JINJA_ENV.from_string(PKG_TMPL)
    for name, settings in packages.items():
        settings = {k.lower(): v for k, v in settings.items()}
        ctx.text = template.render(name=name, **settings)
        fname = "{!s}/{!s}.spec".format(tmpdir, name)
        step_a_file_filepath_with(ctx, fname)
        cmd = "{!s} --define '_rpmdir {!s}' -bb {!s}".format(
            rpmbuild, tmpdir, fname)
        step_i_successfully_run_command(ctx, cmd)
    cmd = "{!s} {!s}".format(createrepo, tmpdir)
    step_i_successfully_run_command(ctx, cmd)

    repofile = REPO_TMPL.format(repository)
    ctx.table = Table(HEADINGS_INI)
    ctx.table.add_row([repository, "name",     repository])
    ctx.table.add_row(["",         "enabled",  "False"])
    ctx.table.add_row(["",         "gpgcheck", "False"])
    ctx.table.add_row(["",         "baseurl",  "file://{!s}".format(tmpdir)])
    step_an_ini_file_filepath_with(ctx, repofile)
def step_gpg_key(ctx, name_real):
    """
    Generates for the root user GPG key with a given identity,
    a.k.a. the Name-Real attribute.

    GPG key attributes can be optionally specified using the table with
    following headers:

    ======= =========
      Tag     Value  
    ======= =========

    Supported GPG key attrubutes are:

    ============= ===============
        Tag       Default value  
    ============= ===============
    Key-Type      RSA            
    Key-Length    2048           
    Subkey-Type   <not present>  
    Subkey-Length <not present>  
    Name-Comment  No Comment     
    Name-Email    dnf@noreply    
    Expire-Date   0              
    =============================

    .. note::
       GPG key configuration is saved in a file /root/${Name-Real}.keyconf
       respective public key is exported to a file /root/${Name-Real}.pubkey

    Examples:

    .. code-block:: gherkin

       Feature: Package signatures

         Scenario: Setup repository with signed packages
           Given GPG key "James Bond"
             And GPG key "James Bond" imported in rpm database
             And repository "TestRepo" with packages signed by "James Bond"
               | Package | Tag | Value |
               | TestA   |     |       |
    """

    if ctx.table:  # additional GPG key configuration listed in the table
        GPGKEY_HEADINGS = ['Tag', 'Value']
        GPGKEY_TAGS = ['Key-Type', 'Key-Length', 'Subkey-Type', 'Subkey-Length', 'Name-Comment', 'Name-Email', 'Expire-Date']
        gpgkey_conf_table = table_utils.parse_kv_table(ctx, GPGKEY_HEADINGS, GPGKEY_TAGS)
    else:  # no table present
        gpgkey_conf_table = {}
    template = JINJA_ENV.from_string(GPGKEY_CONF_TMPL)
    settings = {k.lower().replace('-', '_'): v for k, v in gpgkey_conf_table.items()}
    gpgkey_conf = template.render(name_real=name_real, **settings)
    # write gpgkey configuration to a file
    fpath = GPGKEY_FILEPATH_TMPL.format(name_real, "keyconf")
    with open(fpath, 'w') as fw:
        fw.write(gpgkey_conf)
    # generate the GPG key
    gpgbin = which("gpg2")
    cmd = "{!s} --batch --gen-key '{!s}'".format(gpgbin, fpath)
    step_i_successfully_run_command(ctx, cmd)
    # export the public key
    cmd = "{!s} --export --armor '{!s}'".format(gpgbin, name_real)
    step_i_successfully_run_command(ctx, cmd)
    fpath = GPGKEY_FILEPATH_TMPL.format(name_real, "pubkey")
    with open(fpath, 'w') as fw:
        fw.write(ctx.cmd_result.stdout)
Esempio n. 23
0
def then_update_repository_with_packages(ctx, repository):
    """
    Examples:

       Feature: Working with repositories

         Given I update http repository base with packages
            | Package | Tag | Value |
            | foo     |     |       |

         Given I update http repository "updates" with packages
            | Package | Tag     | Value |
            | foo     | Version |  2.1  |
            | foo v3  | Version |  3.1  |

    """
    packages = table_utils.parse_skv_table(ctx, HEADINGS_REPO, PKG_TAGS,
                                           PKG_TAGS_REPEATING)

    rpmbuild = which("rpmbuild")
    ctx.assertion.assertIsNotNone(rpmbuild, "rpmbuild is required")
    createrepo = which("createrepo_c")
    ctx.assertion.assertIsNotNone(createrepo, "createrepo_c is required")

    repodir = repo_utils.get_repo_dir(repository)
    tmpdir = repodir
    srpm_tmpdir = '{}-source'.format(tmpdir.rstrip('/'))
    template = JINJA_ENV.from_string(PKG_TMPL)
    for name, settings in packages.items():
        name = name.split(
        )[0]  # cut-off the pkg name _suffix_ to allow defining multiple package versions
        disttag = ""
        if '/' in name:  # using the module/pkgname notation, module would be placed to a disttag
            (module, name) = name.split('/', 1)
            disttag = ".{}".format(module)
        # before processing the template
        #   lower all characters
        #   replace '%' in Tag name with '_'
        #   replace '(' in Tag name with '_'
        #   delete all ')' in Tag
        settings = {
            k.lower().replace('%', '_').replace('(', '_').replace(')', ''): v
            for k, v in settings.items()
        }
        ctx.text = template.render(name=name, disttag=disttag, **settings)
        fname = "{!s}/{!s}.spec".format(tmpdir, name)
        step_a_file_filepath_with(ctx, fname)
        buildname = '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}.rpm'
        if 'arch' not in settings or settings['arch'] == 'noarch':
            cmd = "{!s} --define '_rpmdir {!s}' --define '_srcrpmdir {!s}' \
                   --define '_build_name_fmt {!s}' -ba {!s}" \
                   .format(rpmbuild, tmpdir, srpm_tmpdir, buildname, fname)
        else:
            cmd = "setarch {!s} {!s} --define '_rpmdir {!s}' --define '_srcrpmdir {!s}' \
                   --define '_build_name_fmt {!s}' --target {!s} -ba {!s}" \
                   .format(settings['arch'], rpmbuild, tmpdir, srpm_tmpdir, buildname, settings['arch'], fname)
        step_i_successfully_run_command(ctx, cmd)

    file_utils.set_dir_content_ownership(
        ctx, repodir,
        'root')  # change file ownership to root so we can change it
    cmd = "{!s} --update {!s}".format(createrepo, repodir)
    step_i_successfully_run_command(ctx, cmd)
    file_utils.set_dir_content_ownership(ctx,
                                         repodir)  # restore file ownership