Skip to content
This repository has been archived by the owner on Oct 10, 2020. It is now read-only.

Commit

Permalink
syscontainers: add generation of an rpm
Browse files Browse the repository at this point in the history
Add a hidden (for now) option ---generate-rpm to "install --system" to
generate an rpm file instead of installing the container.  The rpm can
be installed on the system and the container won't be managed by
atomic, update and uninstall are disabled.

Differently from containers handled by atomic that installs the
container under /var/lib/containers/atomic, the RPM version installs
its files under /usr/lib/containers and can be integrated in an atomic
image as a normal rpm.

Signed-off-by: Giuseppe Scrivano <[email protected]>

Closes: #767
Approved by: rhatdan
  • Loading branch information
giuseppe authored and rh-atomic-bot committed Mar 22, 2017
1 parent a913074 commit b158ff9
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 18 deletions.
3 changes: 3 additions & 0 deletions Atomic/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ def cli(subparser):
system_xor_user.add_argument("--system", dest="system",
action='store_true', default=False,
help=_('install a system container'))
installp.add_argument("---generate-rpm", dest="generate_rpm",
action='store_true', default=False,
help=_('generate an rpm instead of installing the container'))
installp.add_argument("--rootfs", dest="remote",
help=_("choose an existing exploded container/image to use "
"its rootfs as a remote, read-only rootfs for the "
Expand Down
119 changes: 101 additions & 18 deletions Atomic/syscontainers.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
SYSTEMD_TMPFILES_DEST_USER = "%s/.containers/tmpfiles" % HOME
SYSTEMD_UNIT_FILES_DEST_PREFIX = "%s/usr/lib/systemd/system"
SYSTEMD_TMPFILES_DEST_PREFIX = "%s/usr/lib/tmpfiles.d"
RPM_NAME_PREFIX = "atomic-container"
SYSTEMD_UNIT_FILE_DEFAULT_TEMPLATE = """
[Unit]
Description=$NAME
Expand Down Expand Up @@ -188,6 +189,11 @@ def install(self, image, name):
if self.args.system and self.user:
raise ValueError("Only root can use --system")

if self.args.generate_rpm:
if not self.args.system:
raise ValueError("Only --system can generate rpms")
return self.generate_rpm(repo, name, image)

image = self._pull_image_to_ostree(repo, image, False)

if self.get_checkout(name):
Expand Down Expand Up @@ -476,11 +482,7 @@ def _do_checkout(self, repo, name, img, upgrade, values, destination, unitfileou

if "UUID" not in values:
values["UUID"] = str(uuid.uuid4())
if prefix:
values["DESTDIR"] = os.path.join("/", os.path.relpath(destination, prefix))
else:
values["DESTDIR"] = destination

values["DESTDIR"] = os.path.join("/", os.path.relpath(destination, prefix)) if prefix else destination
values["NAME"] = name
values["EXEC_START"], values["EXEC_STOP"] = self._generate_systemd_startstop_directives(name)
values["HOST_UID"] = os.getuid()
Expand Down Expand Up @@ -570,20 +572,22 @@ def _write_template(inputfilename, data, values, destination):
_write_template(unitfile, tmpfiles_template, values, tmpfilesout)
shutil.copyfile(tmpfilesout, os.path.join(prefix, destination, "tmpfiles-%s.conf" % name))

if not prefix:
sym = "%s/%s" % (self._get_system_checkout_path(), name)
if os.path.exists(sym):
os.unlink(sym)
os.symlink(destination, sym)
if prefix:
return

sym = "%s/%s" % (self._get_system_checkout_path(), name)
if os.path.exists(sym):
os.unlink(sym)
os.symlink(destination, sym)

self._systemctl_command("daemon-reload")
if (tmpfiles_template):
self._systemd_tmpfiles("--create", tmpfilesout)
self._systemctl_command("daemon-reload")
if (tmpfiles_template):
self._systemd_tmpfiles("--create", tmpfilesout)

if not upgrade:
self._systemctl_command("enable", name)
elif was_service_active:
self._systemctl_command("start", name)
if not upgrade:
self._systemctl_command("enable", name)
elif was_service_active:
self._systemctl_command("start", name)

def _get_preinstalled_containers_path(self):
return ATOMIC_USR
Expand Down Expand Up @@ -904,7 +908,8 @@ def get_system_images(self, get_all=False, repo=None):

def _is_service_active(self, name):
try:
return self._systemctl_command("is-active", name, quiet=True).replace("\n", "") == "active"
ret = self._systemctl_command("is-active", name, quiet=True)
return ret and ret.replace("\n", "") == "active"
except subprocess.CalledProcessError:
return False

Expand Down Expand Up @@ -1442,3 +1447,81 @@ def get_out_checksum(obj): return obj.out_checksum if hasattr(obj, 'out_checksum
it.init_commit(repo, repo.load_commit(current_rev)[1], OSTree.RepoCommitTraverseFlags.REPO_COMMIT_TRAVERSE_FLAG_NONE)
traverse(it)
return ret

def generate_rpm(self, repo, name, image):
image_inspect = self.inspect_system_image(image)
temp_dir = tempfile.mkdtemp()
rpm_content = os.path.join(temp_dir, "rpmroot")
rootfs = os.path.join(rpm_content, "usr/lib/containers/atomic", name)
os.makedirs(rootfs)
try:
spec_file = os.path.join(temp_dir, "container.spec")
self._checkout(repo, name, image, 0, False, destination=rootfs, prefix=rpm_content)

if self.display:
return

labels = {k.lower() : v for k, v in image_inspect.get('Labels', {})}
summary = labels.get('summary', name)
version = labels.get("version", "1.0")
release = labels.get("release", "1.0")
license_ = labels.get("license", "GPLv2")
url = labels.get("url")
source0 = labels.get("source0")
requires = labels.get("requires")
provides = labels.get("provides")
conflicts = labels.get("conflicts")
description = labels.get("description")

self._generate_spec_file(spec_file, rpm_content, name, summary, license_, version=version, release=release,
url=url, source0=source0, requires=requires, provides=provides, conflicts=conflicts,
description=description)

cwd = os.getcwd()
cmd = ["rpmbuild", "--noclean", "-bb", spec_file,
"--define", "_sourcedir %s" % temp_dir,
"--define", "_specdir %s" % temp_dir,
"--define", "_builddir %s" % temp_dir,
"--define", "_srcrpmdir %s" % cwd,
"--define", "_rpmdir %s" % cwd,
"--build-in-place",
"--buildroot=%s" % rpm_content]
util.write_out(" ".join(cmd))
if not self.display:
util.check_call(cmd)
return False
finally:
shutil.rmtree(temp_dir)

def _generate_spec_file(self, out, destdir, name, summary, license_, version="1.0", release="1", url=None,
source0=None, requires=None, conflicts=None, provides=None, description=None):
spec = "%global __requires_exclude_from ^.*$\n"
spec = spec + "%global __provides_exclude_from ^.*$\n"

fields = {"Name" : "%s-%s" % (RPM_NAME_PREFIX, name), "Version" : version, "Release" : release, "Summary" : summary,
"License" : license_, "URL" : url, "Source0" : source0, "Requires" : requires,
"Provides" : provides, "Conflicts" : conflicts}
for k, v in fields.items():
if v is not None:
spec = spec + "%s:\t%s\n" % (k, v)

spec = spec + "\n%description\n"
if description:
spec = spec + "%s\n" % description

spec = spec + "\n%files\n"
for root, _, files in os.walk(os.path.join(destdir, "etc")):
rel_path = os.path.relpath(root, destdir)
for f in files:
spec += "%config \"%s\"\n" % os.path.join("/", rel_path, f)

spec += "/usr/lib/containers/atomic/%s\n" % name
for root, _, files in os.walk(os.path.join(destdir, "usr/lib/systemd/system")):
for f in files:
spec = spec + "/usr/lib/systemd/system/%s\n" % f
for root, _, files in os.walk(os.path.join(destdir, "usr/lib/tmpfiles.d")):
for f in files:
spec = spec + "/usr/lib/tmpfiles.d/%s\n" % f

with open(out, "w") as f:
f.write(spec)

0 comments on commit b158ff9

Please sign in to comment.