"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