"Fossies" - the Fresh Open Source Software Archive

Member "salt-3002.2/salt/modules/rpmbuild_pkgbuild.py" (18 Nov 2020, 25104 Bytes) of package /linux/misc/salt-3002.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "rpmbuild_pkgbuild.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3002.1_vs_3002.2.

    1 """
    2 RPM Package builder system
    3 
    4 .. versionadded:: 2015.8.0
    5 
    6 This system allows for all of the components to build rpms safely in chrooted
    7 environments. This also provides a function to generate yum repositories
    8 
    9 This module implements the pkgbuild interface
   10 """
   11 
   12 
   13 import errno
   14 import functools
   15 import logging
   16 import os
   17 import re
   18 import shutil
   19 import tempfile
   20 import time
   21 import traceback
   22 
   23 import salt.utils.files
   24 import salt.utils.path
   25 import salt.utils.user
   26 import salt.utils.vt
   27 from salt.exceptions import CommandExecutionError, SaltInvocationError
   28 from salt.ext.six.moves.urllib.parse import urlparse as _urlparse
   29 
   30 HAS_LIBS = False
   31 
   32 try:
   33     import gnupg  # pylint: disable=unused-import
   34     import salt.modules.gpg
   35 
   36     HAS_LIBS = True
   37 except ImportError:
   38     pass
   39 
   40 log = logging.getLogger(__name__)
   41 
   42 __virtualname__ = "pkgbuild"
   43 
   44 
   45 def __virtual__():
   46     """
   47     Confirm this module is on a RPM based system, and has required utilities
   48     """
   49     missing_util = False
   50     utils_reqd = ["gpg", "rpm", "rpmbuild", "mock", "createrepo"]
   51     for named_util in utils_reqd:
   52         if not salt.utils.path.which(named_util):
   53             missing_util = True
   54             break
   55 
   56     if HAS_LIBS and not missing_util:
   57         if __grains__.get("os_family", False) in ("RedHat", "Suse"):
   58             return __virtualname__
   59         else:
   60             # The module will be exposed as `rpmbuild` on non-RPM based systems
   61             return "rpmbuild"
   62     else:
   63         return (
   64             False,
   65             "The rpmbuild module could not be loaded: requires python-gnupg, "
   66             "gpg, rpm, rpmbuild, mock and createrepo utilities to be installed",
   67         )
   68 
   69 
   70 def _create_rpmmacros(runas="root"):
   71     """
   72     Create the .rpmmacros file in user's home directory
   73     """
   74     home = os.path.expanduser("~" + runas)
   75     rpmbuilddir = os.path.join(home, "rpmbuild")
   76     if not os.path.isdir(rpmbuilddir):
   77         __salt__["file.makedirs_perms"](name=rpmbuilddir, user=runas, group="mock")
   78 
   79     mockdir = os.path.join(home, "mock")
   80     if not os.path.isdir(mockdir):
   81         __salt__["file.makedirs_perms"](name=mockdir, user=runas, group="mock")
   82 
   83     rpmmacros = os.path.join(home, ".rpmmacros")
   84     with salt.utils.files.fopen(rpmmacros, "w") as afile:
   85         afile.write(salt.utils.stringutils.to_str("%_topdir {}\n".format(rpmbuilddir)))
   86         afile.write("%signature gpg\n")
   87         afile.write("%_source_filedigest_algorithm 8\n")
   88         afile.write("%_binary_filedigest_algorithm 8\n")
   89         afile.write("%_gpg_name packaging@saltstack.com\n")
   90 
   91 
   92 def _mk_tree(runas="root"):
   93     """
   94     Create the rpm build tree
   95     """
   96     basedir = tempfile.mkdtemp()
   97     paths = ["BUILD", "RPMS", "SOURCES", "SPECS", "SRPMS"]
   98     for path in paths:
   99         full = os.path.join(basedir, path)
  100         __salt__["file.makedirs_perms"](name=full, user=runas, group="mock")
  101     return basedir
  102 
  103 
  104 def _get_spec(tree_base, spec, template, saltenv="base"):
  105     """
  106     Get the spec file and place it in the SPECS dir
  107     """
  108     spec_tgt = os.path.basename(spec)
  109     dest = os.path.join(tree_base, "SPECS", spec_tgt)
  110     return __salt__["cp.get_url"](spec, dest, saltenv=saltenv)
  111 
  112 
  113 def _get_src(tree_base, source, saltenv="base", runas="root"):
  114     """
  115     Get the named sources and place them into the tree_base
  116     """
  117     parsed = _urlparse(source)
  118     sbase = os.path.basename(source)
  119     dest = os.path.join(tree_base, "SOURCES", sbase)
  120     if parsed.scheme:
  121         lsrc = __salt__["cp.get_url"](source, dest, saltenv=saltenv)
  122     else:
  123         shutil.copy(source, dest)
  124     __salt__["file.chown"](path=dest, user=runas, group="mock")
  125 
  126 
  127 def _get_distset(tgt):
  128     """
  129     Get the distribution string for use with rpmbuild and mock
  130     """
  131     # Centos adds 'centos' string to rpm names, removing that to have
  132     # consistent naming on Centos and Redhat, and allow for Amazon naming
  133     tgtattrs = tgt.split("-")
  134     if tgtattrs[0] == "amzn2":
  135         distset = '--define "dist .{}"'.format(tgtattrs[0])
  136     elif tgtattrs[1] in ["6", "7", "8"]:
  137         distset = '--define "dist .el{}"'.format(tgtattrs[1])
  138     else:
  139         distset = ""
  140 
  141     return distset
  142 
  143 
  144 def _get_deps(deps, tree_base, saltenv="base"):
  145     """
  146     Get include string for list of dependent rpms to build package
  147     """
  148     deps_list = ""
  149     if deps is None:
  150         return deps_list
  151     if not isinstance(deps, list):
  152         raise SaltInvocationError(
  153             "'deps' must be a Python list or comma-separated string"
  154         )
  155     for deprpm in deps:
  156         parsed = _urlparse(deprpm)
  157         depbase = os.path.basename(deprpm)
  158         dest = os.path.join(tree_base, depbase)
  159         if parsed.scheme:
  160             __salt__["cp.get_url"](deprpm, dest, saltenv=saltenv)
  161         else:
  162             shutil.copy(deprpm, dest)
  163 
  164         deps_list += " {}".format(dest)
  165 
  166     return deps_list
  167 
  168 
  169 def _check_repo_gpg_phrase_utils():
  170     """
  171     Check for /usr/libexec/gpg-preset-passphrase is installed
  172     """
  173     util_name = "/usr/libexec/gpg-preset-passphrase"
  174     if __salt__["file.file_exists"](util_name):
  175         return True
  176     else:
  177         raise CommandExecutionError(
  178             "utility '{}' needs to be installed".format(util_name)
  179         )
  180 
  181 
  182 def _get_gpg_key_resources(keyid, env, use_passphrase, gnupghome, runas):
  183     """
  184     Obtain gpg key resource infomation to sign repo files with
  185 
  186     keyid
  187 
  188         Optional Key ID to use in signing packages and repository.
  189         Utilizes Public and Private keys associated with keyid which have
  190         been loaded into the minion's Pillar data.
  191 
  192     env
  193 
  194         A dictionary of environment variables to be utilized in creating the
  195         repository.
  196 
  197     use_passphrase : False
  198 
  199         Use a passphrase with the signing key presented in ``keyid``.
  200         Passphrase is received from Pillar data which could be passed on the
  201         command line with ``pillar`` parameter.
  202 
  203     gnupghome : /etc/salt/gpgkeys
  204 
  205         Location where GPG related files are stored, used with ``keyid``.
  206 
  207     runas : root
  208 
  209         User to create the repository as, and optionally sign packages.
  210 
  211         .. note::
  212 
  213             Ensure the user has correct permissions to any files and
  214             directories which are to be utilized.
  215 
  216 
  217     Returns:
  218         tuple
  219             use_gpg_agent       True | False, Redhat 8 now makes use of a gpg-agent similar ot Debian
  220             local_keyid         key id to use in signing
  221             define_gpg_name     string containing definition to use with addsign (use_gpg_agent False)
  222             phrase              pass phrase (may not be used)
  223 
  224     """
  225     local_keygrip_to_use = None
  226     local_key_fingerprint = None
  227     local_keyid = None
  228     local_uids = None
  229     define_gpg_name = ""
  230     phrase = ""
  231     retrc = 0
  232     use_gpg_agent = False
  233 
  234     if (
  235         __grains__.get("os_family") == "RedHat"
  236         and __grains__.get("osmajorrelease") >= 8
  237     ):
  238         use_gpg_agent = True
  239 
  240     if keyid is not None:
  241         # import_keys
  242         pkg_pub_key_file = "{}/{}".format(
  243             gnupghome, __salt__["pillar.get"]("gpg_pkg_pub_keyname", None)
  244         )
  245         pkg_priv_key_file = "{}/{}".format(
  246             gnupghome, __salt__["pillar.get"]("gpg_pkg_priv_keyname", None)
  247         )
  248 
  249         if pkg_pub_key_file is None or pkg_priv_key_file is None:
  250             raise SaltInvocationError(
  251                 "Pillar data should contain Public and Private keys associated with 'keyid'"
  252             )
  253         try:
  254             __salt__["gpg.import_key"](
  255                 user=runas, filename=pkg_pub_key_file, gnupghome=gnupghome
  256             )
  257             __salt__["gpg.import_key"](
  258                 user=runas, filename=pkg_priv_key_file, gnupghome=gnupghome
  259             )
  260 
  261         except SaltInvocationError:
  262             raise SaltInvocationError(
  263                 "Public and Private key files associated with Pillar data and 'keyid' "
  264                 "{} could not be found".format(keyid)
  265             )
  266 
  267         # gpg keys should have been loaded as part of setup
  268         # retrieve specified key and preset passphrase
  269         local_keys = __salt__["gpg.list_keys"](user=runas, gnupghome=gnupghome)
  270         for gpg_key in local_keys:
  271             if keyid == gpg_key["keyid"][8:]:
  272                 local_uids = gpg_key["uids"]
  273                 local_keyid = gpg_key["keyid"]
  274                 if use_gpg_agent:
  275                     local_keygrip_to_use = gpg_key["fingerprint"]
  276                     local_key_fingerprint = gpg_key["fingerprint"]
  277                 break
  278 
  279         if use_gpg_agent:
  280             cmd = "gpg --with-keygrip --list-secret-keys"
  281             local_keys2_keygrip = __salt__["cmd.run"](cmd, runas=runas, env=env)
  282             local_keys2 = iter(local_keys2_keygrip.splitlines())
  283             try:
  284                 for line in local_keys2:
  285                     if line.startswith("sec"):
  286                         line_fingerprint = next(local_keys2).lstrip().rstrip()
  287                         if local_key_fingerprint == line_fingerprint:
  288                             lkeygrip = next(local_keys2).split("=")
  289                             local_keygrip_to_use = lkeygrip[1].lstrip().rstrip()
  290                             break
  291             except StopIteration:
  292                 raise SaltInvocationError(
  293                     "unable to find keygrip associated with fingerprint '{}' for keyid '{}'".format(
  294                         local_key_fingerprint, local_keyid
  295                     )
  296                 )
  297 
  298         if local_keyid is None:
  299             raise SaltInvocationError(
  300                 "The key ID '{}' was not found in GnuPG keyring at '{}'".format(
  301                     keyid, gnupghome
  302                 )
  303             )
  304 
  305         if use_passphrase:
  306             phrase = __salt__["pillar.get"]("gpg_passphrase")
  307             if use_gpg_agent:
  308                 _check_repo_gpg_phrase_utils()
  309                 cmd = (
  310                     "/usr/libexec/gpg-preset-passphrase --verbose --preset "
  311                     '--passphrase "{}" {}'.format(phrase, local_keygrip_to_use)
  312                 )
  313                 retrc = __salt__["cmd.retcode"](cmd, runas=runas, env=env)
  314                 if retrc != 0:
  315                     raise SaltInvocationError(
  316                         "Failed to preset passphrase, error {1}, "
  317                         "check logs for further details".format(retrc)
  318                     )
  319 
  320         if local_uids:
  321             define_gpg_name = "--define='%_signature gpg' --define='%_gpg_name {}'".format(
  322                 local_uids[0]
  323             )
  324 
  325         # need to update rpm with public key
  326         cmd = "rpm --import {}".format(pkg_pub_key_file)
  327         retrc = __salt__["cmd.retcode"](cmd, runas=runas, use_vt=True)
  328         if retrc != 0:
  329             raise SaltInvocationError(
  330                 "Failed to import public key from file {} with return "
  331                 "error {}, check logs for further details".format(
  332                     pkg_pub_key_file, retrc
  333                 )
  334             )
  335 
  336     return (use_gpg_agent, local_keyid, define_gpg_name, phrase)
  337 
  338 
  339 def _sign_file(runas, define_gpg_name, phrase, abs_file, timeout):
  340     """
  341     Sign file with provided key and definition
  342     """
  343     SIGN_PROMPT_RE = re.compile(r"Enter pass phrase: ", re.M)
  344 
  345     # interval of 0.125 is really too fast on some systems
  346     interval = 0.5
  347     number_retries = timeout / interval
  348     times_looped = 0
  349     error_msg = "Failed to sign file {}".format(abs_file)
  350 
  351     cmd = "rpm {} --addsign {}".format(define_gpg_name, abs_file)
  352     preexec_fn = functools.partial(salt.utils.user.chugid_and_umask, runas, None)
  353     try:
  354         stdout, stderr = None, None
  355         proc = salt.utils.vt.Terminal(
  356             cmd,
  357             shell=True,
  358             preexec_fn=preexec_fn,
  359             stream_stdout=True,
  360             stream_stderr=True,
  361         )
  362         while proc.has_unread_data:
  363             stdout, stderr = proc.recv()
  364             if stdout and SIGN_PROMPT_RE.search(stdout):
  365                 # have the prompt for inputting the passphrase
  366                 proc.sendline(phrase)
  367             else:
  368                 times_looped += 1
  369 
  370             if times_looped > number_retries:
  371                 raise SaltInvocationError(
  372                     "Attemping to sign file {} failed, timed out after {} seconds".format(
  373                         abs_file, int(times_looped * interval)
  374                     )
  375                 )
  376             time.sleep(interval)
  377 
  378         proc_exitstatus = proc.exitstatus
  379         if proc_exitstatus != 0:
  380             raise SaltInvocationError(
  381                 "Signing file {} failed with proc.status {}".format(
  382                     abs_file, proc_exitstatus
  383                 )
  384             )
  385     except salt.utils.vt.TerminalException as err:
  386         trace = traceback.format_exc()
  387         log.error(error_msg, err, trace)
  388     finally:
  389         proc.close(terminate=True, kill=True)
  390 
  391 
  392 def _sign_files_with_gpg_agent(runas, local_keyid, abs_file, repodir, env, timeout):
  393     """
  394     Sign file with provided key utilizing gpg-agent
  395     """
  396     cmd = "rpmsign --verbose  --key-id={} --addsign {}".format(local_keyid, abs_file)
  397     retrc = __salt__["cmd.retcode"](cmd, runas=runas, cwd=repodir, use_vt=True, env=env)
  398     if retrc != 0:
  399         raise SaltInvocationError(
  400             "Signing encountered errors for command '{}', "
  401             "return error {}, check logs for further details".format(cmd, retrc)
  402         )
  403 
  404 
  405 def make_src_pkg(
  406     dest_dir, spec, sources, env=None, template=None, saltenv="base", runas="root"
  407 ):
  408     """
  409     Create a source rpm from the given spec file and sources
  410 
  411     CLI Example:
  412 
  413     .. code-block:: bash
  414 
  415         salt '*' pkgbuild.make_src_pkg /var/www/html/
  416                 https://raw.githubusercontent.com/saltstack/libnacl/master/pkg/rpm/python-libnacl.spec
  417                 https://pypi.python.org/packages/source/l/libnacl/libnacl-1.3.5.tar.gz
  418 
  419     This example command should build the libnacl SOURCE package and place it in
  420     /var/www/html/ on the minion
  421 
  422     .. versionchanged:: 2017.7.0
  423 
  424     dest_dir
  425         The directory on the minion to place the built package(s)
  426 
  427     spec
  428         The location of the spec file (used for rpms)
  429 
  430     sources
  431         The list of package sources
  432 
  433     env
  434         A dictionary of environment variables to be set prior to execution.
  435 
  436     template
  437         Run the spec file through a templating engine
  438         Optional argument, allows for no templating engine used to be
  439         if none is desired.
  440 
  441     saltenv
  442         The saltenv to use for files downloaded from the salt filesever
  443 
  444     runas
  445         The user to run the build process as
  446 
  447         .. versionadded:: 2018.3.3
  448 
  449 
  450     .. note::
  451 
  452         using SHA256 as digest and minimum level dist el6
  453 
  454     """
  455     _create_rpmmacros(runas)
  456     tree_base = _mk_tree(runas)
  457     spec_path = _get_spec(tree_base, spec, template, saltenv)
  458     __salt__["file.chown"](path=spec_path, user=runas, group="mock")
  459     __salt__["file.chown"](path=tree_base, user=runas, group="mock")
  460 
  461     if isinstance(sources, str):
  462         sources = sources.split(",")
  463     for src in sources:
  464         _get_src(tree_base, src, saltenv, runas)
  465 
  466     # make source rpms for dist el6 with SHA256, usable with mock on other dists
  467     cmd = 'rpmbuild --verbose --define "_topdir {}" -bs --define "dist .el6" {}'.format(
  468         tree_base, spec_path
  469     )
  470     retrc = __salt__["cmd.retcode"](cmd, runas=runas)
  471     if retrc != 0:
  472         raise SaltInvocationError(
  473             "Make source package for destination directory {}, spec {}, sources {}, failed "
  474             "with return error {}, check logs for further details".format(
  475                 dest_dir, spec, sources, retrc
  476             )
  477         )
  478 
  479     srpms = os.path.join(tree_base, "SRPMS")
  480     ret = []
  481     if not os.path.isdir(dest_dir):
  482         __salt__["file.makedirs_perms"](name=dest_dir, user=runas, group="mock")
  483     for fn_ in os.listdir(srpms):
  484         full = os.path.join(srpms, fn_)
  485         tgt = os.path.join(dest_dir, fn_)
  486         shutil.copy(full, tgt)
  487         ret.append(tgt)
  488     return ret
  489 
  490 
  491 def build(
  492     runas,
  493     tgt,
  494     dest_dir,
  495     spec,
  496     sources,
  497     deps,
  498     env,
  499     template,
  500     saltenv="base",
  501     log_dir="/var/log/salt/pkgbuild",
  502 ):
  503     """
  504     Given the package destination directory, the spec file source and package
  505     sources, use mock to safely build the rpm defined in the spec file
  506 
  507     CLI Example:
  508 
  509     .. code-block:: bash
  510 
  511         salt '*' pkgbuild.build mock epel-7-x86_64 /var/www/html
  512                     https://raw.githubusercontent.com/saltstack/libnacl/master/pkg/rpm/python-libnacl.spec
  513                     https://pypi.python.org/packages/source/l/libnacl/libnacl-1.3.5.tar.gz
  514 
  515     This example command should build the libnacl package for rhel 7 using user
  516     mock and place it in /var/www/html/ on the minion
  517     """
  518     ret = {}
  519     try:
  520         __salt__["file.chown"](path=dest_dir, user=runas, group="mock")
  521     except OSError as exc:
  522         if exc.errno != errno.EEXIST:
  523             raise
  524     srpm_dir = os.path.join(dest_dir, "SRPMS")
  525     srpm_build_dir = tempfile.mkdtemp()
  526     try:
  527         srpms = make_src_pkg(
  528             srpm_build_dir, spec, sources, env, template, saltenv, runas
  529         )
  530     except Exception as exc:  # pylint: disable=broad-except
  531         shutil.rmtree(srpm_build_dir)
  532         log.error("Failed to make src package")
  533         return ret
  534 
  535     distset = _get_distset(tgt)
  536 
  537     noclean = ""
  538     deps_dir = tempfile.mkdtemp()
  539     deps_list = _get_deps(deps, deps_dir, saltenv)
  540 
  541     retrc = 0
  542     for srpm in srpms:
  543         dbase = os.path.dirname(srpm)
  544         results_dir = tempfile.mkdtemp()
  545         try:
  546             __salt__["file.chown"](path=dbase, user=runas, group="mock")
  547             __salt__["file.chown"](path=results_dir, user=runas, group="mock")
  548             cmd = "mock --root={} --resultdir={} --init".format(tgt, results_dir)
  549             retrc |= __salt__["cmd.retcode"](cmd, runas=runas)
  550             if deps_list and not deps_list.isspace():
  551                 cmd = "mock --root={} --resultdir={} --install {} {}".format(
  552                     tgt, results_dir, deps_list, noclean
  553                 )
  554                 retrc |= __salt__["cmd.retcode"](cmd, runas=runas)
  555                 noclean += " --no-clean"
  556 
  557             cmd = "mock --root={} --resultdir={} {} {} {}".format(
  558                 tgt, results_dir, distset, noclean, srpm
  559             )
  560             retrc |= __salt__["cmd.retcode"](cmd, runas=runas)
  561             cmdlist = [
  562                 "rpm",
  563                 "-qp",
  564                 "--queryformat",
  565                 "{0}/%{{name}}/%{{version}}-%{{release}}".format(log_dir),
  566                 srpm,
  567             ]
  568             log_dest = __salt__["cmd.run_stdout"](cmdlist, python_shell=False)
  569             for filename in os.listdir(results_dir):
  570                 full = os.path.join(results_dir, filename)
  571                 if filename.endswith("src.rpm"):
  572                     sdest = os.path.join(srpm_dir, filename)
  573                     try:
  574                         __salt__["file.makedirs_perms"](
  575                             name=srpm_dir, user=runas, group="mock"
  576                         )
  577                     except OSError as exc:
  578                         if exc.errno != errno.EEXIST:
  579                             raise
  580                     shutil.copy(full, sdest)
  581                     ret.setdefault("Source Packages", []).append(sdest)
  582                 elif filename.endswith(".rpm"):
  583                     bdist = os.path.join(dest_dir, filename)
  584                     shutil.copy(full, bdist)
  585                     ret.setdefault("Packages", []).append(bdist)
  586                 else:
  587                     log_file = os.path.join(log_dest, filename)
  588                     try:
  589                         __salt__["file.makedirs_perms"](
  590                             name=log_dest, user=runas, group="mock"
  591                         )
  592                     except OSError as exc:
  593                         if exc.errno != errno.EEXIST:
  594                             raise
  595                     shutil.copy(full, log_file)
  596                     ret.setdefault("Log Files", []).append(log_file)
  597         except Exception as exc:  # pylint: disable=broad-except
  598             log.error("Error building from %s: %s", srpm, exc)
  599         finally:
  600             shutil.rmtree(results_dir)
  601     if retrc != 0:
  602         raise SaltInvocationError(
  603             "Building packages for destination directory {}, spec {}, sources {}, failed "
  604             "with return error {}, check logs for further details".format(
  605                 dest_dir, spec, sources, retrc
  606             )
  607         )
  608     shutil.rmtree(deps_dir)
  609     shutil.rmtree(srpm_build_dir)
  610     return ret
  611 
  612 
  613 def make_repo(
  614     repodir,
  615     keyid=None,
  616     env=None,
  617     use_passphrase=False,
  618     gnupghome="/etc/salt/gpgkeys",
  619     runas="root",
  620     timeout=15.0,
  621 ):
  622     """
  623     Make a package repository and optionally sign packages present
  624 
  625     Given the repodir, create a ``yum`` repository out of the rpms therein
  626     and optionally sign it and packages present, the name is directory to
  627     turn into a repo. This state is best used with onchanges linked to
  628     your package building states.
  629 
  630     repodir
  631         The directory to find packages that will be in the repository.
  632 
  633     keyid
  634         .. versionchanged:: 2016.3.0
  635 
  636         Optional Key ID to use in signing packages and repository.
  637         Utilizes Public and Private keys associated with keyid which have
  638         been loaded into the minion's Pillar data.
  639 
  640         For example, contents from a Pillar data file with named Public
  641         and Private keys as follows:
  642 
  643         .. code-block:: yaml
  644 
  645             gpg_pkg_priv_key: |
  646               -----BEGIN PGP PRIVATE KEY BLOCK-----
  647               Version: GnuPG v1
  648 
  649               lQO+BFciIfQBCADAPCtzx7I5Rl32escCMZsPzaEKWe7bIX1em4KCKkBoX47IG54b
  650               w82PCE8Y1jF/9Uk2m3RKVWp3YcLlc7Ap3gj6VO4ysvVz28UbnhPxsIkOlf2cq8qc
  651               .
  652               .
  653               Ebe+8JCQTwqSXPRTzXmy/b5WXDeM79CkLWvuGpXFor76D+ECMRPv/rawukEcNptn
  654               R5OmgHqvydEnO4pWbn8JzQO9YX/Us0SMHBVzLC8eIi5ZIopzalvX
  655               =JvW8
  656               -----END PGP PRIVATE KEY BLOCK-----
  657 
  658             gpg_pkg_priv_keyname: gpg_pkg_key.pem
  659 
  660             gpg_pkg_pub_key: |
  661               -----BEGIN PGP PUBLIC KEY BLOCK-----
  662               Version: GnuPG v1
  663 
  664               mQENBFciIfQBCADAPCtzx7I5Rl32escCMZsPzaEKWe7bIX1em4KCKkBoX47IG54b
  665               w82PCE8Y1jF/9Uk2m3RKVWp3YcLlc7Ap3gj6VO4ysvVz28UbnhPxsIkOlf2cq8qc
  666               .
  667               .
  668               bYP7t5iwJmQzRMyFInYRt77wkJBPCpJc9FPNebL9vlZcN4zv0KQta+4alcWivvoP
  669               4QIxE+/+trC6QRw2m2dHk6aAeq/J0Sc7ilZufwnNA71hf9SzRIwcFXMsLx4iLlki
  670               inNqW9c=
  671               =s1CX
  672               -----END PGP PUBLIC KEY BLOCK-----
  673 
  674             gpg_pkg_pub_keyname: gpg_pkg_key.pub
  675 
  676     env
  677         .. versionchanged:: 2016.3.0
  678 
  679         A dictionary of environment variables to be utilized in creating the
  680         repository.
  681 
  682         .. note::
  683 
  684             This parameter is not used for making ``yum`` repositories.
  685 
  686     use_passphrase : False
  687         .. versionadded:: 2016.3.0
  688 
  689         Use a passphrase with the signing key presented in ``keyid``.
  690         Passphrase is received from Pillar data which could be passed on the
  691         command line with ``pillar`` parameter.
  692 
  693         .. code-block:: bash
  694 
  695             pillar='{ "gpg_passphrase" : "my_passphrase" }'
  696 
  697         .. versionadded:: 3001.1
  698 
  699         RHEL 8 and above leverages gpg-agent and gpg-preset-passphrase for
  700         caching keys, etc.
  701 
  702     gnupghome : /etc/salt/gpgkeys
  703         .. versionadded:: 2016.3.0
  704 
  705         Location where GPG related files are stored, used with ``keyid``.
  706 
  707     runas : root
  708         .. versionadded:: 2016.3.0
  709 
  710         User to create the repository as, and optionally sign packages.
  711 
  712         .. note::
  713 
  714             Ensure the user has correct permissions to any files and
  715             directories which are to be utilized.
  716 
  717     timeout : 15.0
  718         .. versionadded:: 2016.3.4
  719 
  720         Timeout in seconds to wait for the prompt for inputting the passphrase.
  721 
  722     CLI Example:
  723 
  724     .. code-block:: bash
  725 
  726         salt '*' pkgbuild.make_repo /var/www/html/
  727 
  728     """
  729     home = os.path.expanduser("~" + runas)
  730     rpmmacros = os.path.join(home, ".rpmmacros")
  731     if not os.path.exists(rpmmacros):
  732         _create_rpmmacros(runas)
  733 
  734     if gnupghome and env is None:
  735         env = {}
  736         env["GNUPGHOME"] = gnupghome
  737 
  738     use_gpg_agent, local_keyid, define_gpg_name, phrase = _get_gpg_key_resources(
  739         keyid, env, use_passphrase, gnupghome, runas
  740     )
  741 
  742     # sign_it_here
  743     for fileused in os.listdir(repodir):
  744         if fileused.endswith(".rpm"):
  745             abs_file = os.path.join(repodir, fileused)
  746             if use_gpg_agent:
  747                 _sign_files_with_gpg_agent(
  748                     runas, local_keyid, abs_file, repodir, env, timeout
  749                 )
  750             else:
  751                 _sign_file(runas, define_gpg_name, phrase, abs_file, timeout)
  752 
  753     cmd = "createrepo --update {}".format(repodir)
  754     retrc = __salt__["cmd.run_all"](cmd, runas=runas)
  755     return retrc