mirror of
https://github.com/projectatomic/atomic.git
synced 2026-02-06 03:45:28 +01:00
Change the install data format to keep a list of containers for each image installed, so that multiple containers for the same image can be installed and uninstalled. Closes: https://bugzilla.redhat.com/show_bug.cgi?id=1559935 Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com> Closes: #1214 Approved by: baude
189 lines
8.5 KiB
Python
189 lines
8.5 KiB
Python
import argparse
|
|
import re
|
|
import sys
|
|
from . import util
|
|
from .util import add_opt
|
|
from .syscontainers import OSTREE_PRESENT
|
|
from Atomic.backendutils import BackendUtils
|
|
from Atomic.discovery import RegistryInspectError
|
|
from time import gmtime, strftime
|
|
|
|
try:
|
|
from . import Atomic
|
|
except ImportError:
|
|
from atomic import Atomic # pylint: disable=relative-import
|
|
|
|
INSTALL_ARGS = ["run",
|
|
"-t",
|
|
"-i",
|
|
"--rm",
|
|
"--privileged",
|
|
"-v", "/:/host",
|
|
"--net=host",
|
|
"--ipc=host",
|
|
"--pid=host",
|
|
"-e", "HOST=/host",
|
|
"-e", "NAME=${NAME}",
|
|
"-e", "IMAGE=${IMAGE}",
|
|
"-e", "CONFDIR=/host/etc/${NAME}",
|
|
"-e", "LOGDIR=/host/var/log/${NAME}",
|
|
"-e", "DATADIR=/host/var/lib/${NAME}",
|
|
"-e", "SYSTEMD_IGNORE_CHROOT=1",
|
|
"--name", "${NAME}",
|
|
"${IMAGE}"]
|
|
|
|
ATOMIC_CONFIG = util.get_atomic_config()
|
|
_storage = ATOMIC_CONFIG.get('default_storage', "docker")
|
|
|
|
def cli(subparser):
|
|
# atomic install
|
|
installp = subparser.add_parser(
|
|
"install", help=_("execute container image install method"),
|
|
epilog="atomic install attempts to read the LABEL INSTALL field "
|
|
"in the image, if it does not exist atomic will just pull "
|
|
"the image on to your machine. You could add a LABEL "
|
|
"INSTALL command to your Dockerfile like: 'LABEL INSTALL "
|
|
"%s'" % Install.print_install())
|
|
installp.set_defaults(_class=Install, func='install')
|
|
add_opt(installp)
|
|
installp.add_argument("--storage", dest="storage", default=None,
|
|
help=_("Specify the storage. Default is currently '%s'. You can"
|
|
" change the default by editing /etc/atomic.conf and changing"
|
|
" the 'default_storage' field." % _storage))
|
|
installp.add_argument("-n", "--name", dest="name", default=None,
|
|
help=_("name of container"))
|
|
installp.add_argument(
|
|
"--display",
|
|
default=False,
|
|
action="store_true",
|
|
help=_("preview the command that %s would execute") % sys.argv[0])
|
|
installp.add_argument("image", help=_("container image"))
|
|
if OSTREE_PRESENT:
|
|
system_xor_user = installp.add_mutually_exclusive_group()
|
|
system_xor_user.add_argument("--user", dest="user", action="store_true", default=False,
|
|
help=_("install the image as an user image."))
|
|
system_xor_user.add_argument("--system", dest="system",
|
|
action='store_true', default=False,
|
|
help=_('install a system container'))
|
|
installp.add_argument("--runtime", dest="runtime", default=None,
|
|
help=_('specify the OCI runtime to use for system and user containers'))
|
|
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 "
|
|
"container to be installed"))
|
|
installp.add_argument("--set", dest="setvalues",
|
|
action='append',
|
|
help=_("specify a variable in the VARIABLE=VALUE "
|
|
"form for a system container"))
|
|
installp.add_argument("--system-package", dest="system_package", default="auto",
|
|
help=_('control how to install the package. It accepts `auto`, `yes`, `no`, `build`'))
|
|
installp.add_argument("args", nargs=argparse.REMAINDER,
|
|
help=_("additional arguments appended to the image "
|
|
"install method"))
|
|
|
|
|
|
class Install(Atomic):
|
|
def install(self):
|
|
if self.args.debug:
|
|
util.write_out(str(self.args))
|
|
storage_set = False if self.args.storage is None else True
|
|
storage = _storage if not storage_set else self.args.storage
|
|
args_system = getattr(self.args, 'system', None)
|
|
args_user = getattr(self.args, 'user', None)
|
|
if (args_system or args_user) and storage != 'ostree' and storage_set:
|
|
raise ValueError("The --system and --user options are only available for the 'ostree' storage.")
|
|
be_utils = BackendUtils()
|
|
try:
|
|
# Check to see if the container already exists
|
|
_, _ = be_utils.get_backend_and_container_obj(self.name)
|
|
raise ValueError("A container '%s' is already present" % self.name)
|
|
except ValueError:
|
|
pass
|
|
|
|
if self.user:
|
|
if not util.is_user_mode():
|
|
raise ValueError("--user does not work for privileged user")
|
|
return self.syscontainers.install_user_container(self.image, self.name)
|
|
if self.ostree_uri(self.image):
|
|
return self.syscontainers.install(self.image, self.name)
|
|
# Check if image exists
|
|
str_backend = 'ostree' if args_system else self.args.storage or storage
|
|
be = be_utils.get_backend_from_string(str_backend)
|
|
img_obj = be.has_image(self.args.image)
|
|
if img_obj and img_obj.is_system_type:
|
|
be = be_utils.get_backend_from_string('ostree')
|
|
|
|
if img_obj is None:
|
|
# Unable to find the image locally, look remotely
|
|
remote_image_obj = be.make_remote_image(self.args.image)
|
|
# We found an atomic.type of system, therefore install it onto the ostree
|
|
# backend
|
|
if remote_image_obj.is_system_type and not storage_set and not (args_system or args_user):
|
|
be_utils.message_backend_change('docker', 'ostree')
|
|
be = be_utils.get_backend_from_string('ostree')
|
|
be.pull_image(self.args.image, remote_image_obj, debug=self.args.debug)
|
|
img_obj = be.has_image(self.image)
|
|
|
|
if be.backend is not 'docker':
|
|
if OSTREE_PRESENT and self.args.setvalues and not self.user and not self.system:
|
|
raise ValueError("--set is valid only when used with --system or --user")
|
|
|
|
# We need to fix this long term and get ostree
|
|
# using the backend approach vs the atomic args
|
|
be.syscontainers.set_args(self.args)
|
|
return be.install(self.image, self.name)
|
|
|
|
installation = None
|
|
if storage == 'docker' and not args_system:
|
|
if self.args.system_package == 'build':
|
|
raise ValueError("'--system-package=build' is not supported for docker backend")
|
|
installation = be.rpm_install(img_obj, self.name)
|
|
|
|
install_args = img_obj.get_label('INSTALL')
|
|
|
|
if installation or install_args:
|
|
try:
|
|
name = img_obj.fq_name
|
|
except RegistryInspectError:
|
|
name = img_obj.input_name
|
|
install_data_content = {
|
|
'id': img_obj.id,
|
|
"container_name": self.name,
|
|
'install_date': strftime("%Y-%m-%d %H:%M:%S", gmtime())
|
|
}
|
|
if installation:
|
|
# let's fail the installation if rpm for this image is already installed
|
|
if util.InstallData.image_installed(img_obj):
|
|
raise ValueError("Image {} is already installed.".format(self.image))
|
|
install_data_content["rpm_installed_files"] = installation.installed_files
|
|
rpm_nvra = re.sub(r"\.rpm$", "", installation.original_rpm_name)
|
|
install_data_content["system_package_nvra"] = rpm_nvra
|
|
install_data = {name: install_data_content}
|
|
|
|
if not install_args:
|
|
return 0
|
|
install_args = install_args.split()
|
|
cmd = self.sub_env_strings(self.gen_cmd(install_args + self.quote(self.args.args)))
|
|
self.display(cmd)
|
|
|
|
if not self.args.display:
|
|
result = util.check_call(cmd)
|
|
if result == 0:
|
|
if installation or install_args:
|
|
# Only write the install data if the installation worked.
|
|
util.InstallData.write_install_data(install_data, append=True)
|
|
return result
|
|
|
|
|
|
|
|
@staticmethod
|
|
def print_install():
|
|
return "%s %s %s" % (util.default_docker(), " ".join(INSTALL_ARGS), "/usr/bin/INSTALLCMD")
|
|
|
|
@staticmethod
|
|
def ostree_uri(image_name):
|
|
for i in ['dockertar:', 'docker:']:
|
|
if image_name.startswith(i):
|
|
return True
|
|
return False
|