parent
044b8da55a
commit
5fc7d033f9
288 changed files with 13040 additions and 1 deletions
303
bots/images/scripts/lib/atomic.install
Executable file
303
bots/images/scripts/lib/atomic.install
Executable file
|
|
@ -0,0 +1,303 @@
|
|||
#!/usr/bin/python2
|
||||
|
||||
# This file is part of Cockpit.
|
||||
#
|
||||
# Copyright (C) 2015 Red Hat, Inc.
|
||||
#
|
||||
# Cockpit is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Cockpit is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
try:
|
||||
from urllib.request import URLopener
|
||||
except ImportError:
|
||||
from urllib import URLopener # Python 2
|
||||
import argparse
|
||||
import json
|
||||
|
||||
BASEDIR = os.path.dirname(__file__)
|
||||
|
||||
class AtomicCockpitInstaller:
|
||||
branch = None
|
||||
checkout_location = "/var/local-tree"
|
||||
repo_location = "/var/local-repo"
|
||||
rpm_location = "/usr/share/rpm"
|
||||
key_id = "95A8BA1754D0E95E2B3A98A7EE15015654780CBD"
|
||||
port = 12345
|
||||
|
||||
# Support installing random packages if needed.
|
||||
external_packages = {}
|
||||
|
||||
# Temporarily force cockpit-system instead of cockpit-shell
|
||||
packages_force_install = [ "cockpit-system",
|
||||
"cockpit-docker",
|
||||
"cockpit-kdump",
|
||||
"cockpit-networkmanager",
|
||||
"cockpit-sosreport" ]
|
||||
|
||||
def __init__(self, rpms=None, extra_rpms=None, verbose=False):
|
||||
self.verbose = verbose
|
||||
self.rpms = rpms
|
||||
self.extra_rpms = extra_rpms
|
||||
status = json.loads(subprocess.check_output(["rpm-ostree", "status", "--json"], universal_newlines=True))
|
||||
origin = None
|
||||
for deployment in status.get("deployments", []):
|
||||
if deployment.get("booted"):
|
||||
origin = deployment["origin"]
|
||||
|
||||
if not origin:
|
||||
raise Exception("Couldn't find origin")
|
||||
|
||||
self.branch = origin.split(":", 1)[-1]
|
||||
|
||||
def setup_dirs(self):
|
||||
if self.verbose:
|
||||
print("setting up new ostree repo")
|
||||
|
||||
try:
|
||||
shutil.rmtree(self.repo_location)
|
||||
except:
|
||||
pass
|
||||
|
||||
os.makedirs(self.repo_location)
|
||||
subprocess.check_call(["ostree", "init", "--repo", self.repo_location,
|
||||
"--mode", "archive-z2"])
|
||||
|
||||
if not os.path.exists(self.checkout_location):
|
||||
if self.verbose:
|
||||
print("cloning current branch")
|
||||
|
||||
subprocess.check_call(["ostree", "checkout", self.branch,
|
||||
self.checkout_location])
|
||||
|
||||
# move /usr/etc to /etc, makes rpm installs easier
|
||||
subprocess.check_call(["mv", os.path.join(self.checkout_location, "usr", "etc"),
|
||||
os.path.join(self.checkout_location, "etc")])
|
||||
|
||||
def switch_to_local_tree(self):
|
||||
if self.verbose:
|
||||
print("install new ostree commit")
|
||||
|
||||
# Not an error if this fails
|
||||
subprocess.call(["ostree", "remote", "delete", "local"])
|
||||
|
||||
subprocess.check_call(["ostree", "remote", "add", "local",
|
||||
"file://{}".format(self.repo_location),
|
||||
"--no-gpg-verify"])
|
||||
|
||||
# HACK: https://github.com/candlepin/subscription-manager/issues/1404
|
||||
subprocess.call(["systemctl", "disable", "rhsmcertd"])
|
||||
subprocess.call(["systemctl", "stop", "rhsmcertd"])
|
||||
|
||||
status = subprocess.check_output(["rpm-ostree", "status"])
|
||||
if b"local:" in status:
|
||||
subprocess.check_call(["rpm-ostree", "upgrade"])
|
||||
else:
|
||||
try:
|
||||
subprocess.check_call(["setenforce", "0"])
|
||||
subprocess.check_call(["rpm-ostree", "rebase",
|
||||
"local:{0}".format(self.branch)])
|
||||
except:
|
||||
os.system("sysctl kernel.core_pattern")
|
||||
os.system("coredumpctl || true")
|
||||
raise
|
||||
finally:
|
||||
subprocess.check_call(["setenforce", "1"])
|
||||
|
||||
def commit_to_repo(self):
|
||||
if self.verbose:
|
||||
print("commit package changes to our repo")
|
||||
|
||||
# move etc back to /usr/etc
|
||||
subprocess.check_call(["mv", os.path.join(self.checkout_location, "etc"),
|
||||
os.path.join(self.checkout_location, "usr", "etc")])
|
||||
|
||||
subprocess.check_call(["ostree", "commit", "-s", "cockpit-tree",
|
||||
"--repo", self.repo_location,
|
||||
"-b", self.branch,
|
||||
"--add-metadata-string", "version=cockpit-base.1",
|
||||
"--tree=dir={0}".format(self.checkout_location),
|
||||
"--gpg-sign={0}".format(self.key_id),
|
||||
"--gpg-homedir={0}".format(BASEDIR)])
|
||||
|
||||
def install_packages(self, packages, deps=True, replace=False):
|
||||
args = ["rpm", "-U", "--root", self.checkout_location,
|
||||
"--dbpath", self.rpm_location]
|
||||
|
||||
if replace:
|
||||
args.extend(["--replacepkgs", "--replacefiles"])
|
||||
|
||||
if not deps:
|
||||
args.append("--nodeps")
|
||||
|
||||
for package in packages:
|
||||
args.append(os.path.abspath(os.path.join(os.getcwd(), package)))
|
||||
|
||||
subprocess.check_call(args)
|
||||
|
||||
def remove_packages(self, packages):
|
||||
args = ["rpm", "-e", "--root", self.checkout_location,
|
||||
"--dbpath", self.rpm_location]
|
||||
args.extend(packages)
|
||||
subprocess.check_call(args)
|
||||
|
||||
def package_basename(self, package):
|
||||
""" only accept package with the name 'cockpit-%s-*' and return 'cockpit-%s' or None"""
|
||||
basename = "-".join(package.split("-")[:2])
|
||||
if basename.startswith("cockpit-"):
|
||||
return basename
|
||||
else:
|
||||
return None
|
||||
|
||||
def update_container(self):
|
||||
""" Install the latest cockpit RPMs in our container"""
|
||||
rpm_args = []
|
||||
for package in self.rpms:
|
||||
if 'cockpit-ws' in package or 'cockpit-dashboard' in package or 'cockpit-bridge' in package:
|
||||
rpm_args.append("/host" + package)
|
||||
extra_args = []
|
||||
for package in self.extra_rpms:
|
||||
extra_args.append("/host" + package)
|
||||
|
||||
if rpm_args:
|
||||
subprocess.check_call(["docker", "run", "--name", "build-cockpit",
|
||||
"-d", "--privileged", "-v", "/:/host",
|
||||
"cockpit/ws", "sleep", "1d"])
|
||||
if self.verbose:
|
||||
print("updating cockpit-ws container")
|
||||
|
||||
if extra_args:
|
||||
subprocess.check_call(["docker", "exec", "build-cockpit",
|
||||
"rpm", "--install", "--verbose", "--force"] + extra_args)
|
||||
|
||||
subprocess.check_call(["docker", "exec", "build-cockpit",
|
||||
"rpm", "--freshen", "--verbose", "--force"] + rpm_args)
|
||||
|
||||
# if we update the RPMs, also update the scripts, to keep them in sync
|
||||
subprocess.check_call(["docker", "exec", "build-cockpit", "sh", "-exc",
|
||||
"cp /host/var/tmp/containers/ws/atomic-* /container/"])
|
||||
|
||||
subprocess.check_call(["docker", "commit", "build-cockpit",
|
||||
"cockpit/ws"])
|
||||
subprocess.check_call(["docker", "kill", "build-cockpit"])
|
||||
subprocess.check_call(["docker", "rm", "build-cockpit"])
|
||||
|
||||
def package_basenames(self, package_names):
|
||||
""" convert a list of package names to a list of their basenames """
|
||||
return list(filter(lambda s: s is not None, map(self.package_basename, package_names)))
|
||||
|
||||
def get_installed_cockpit_packages(self):
|
||||
""" get list installed cockpit packages """
|
||||
packages = subprocess.check_output("rpm -qa | grep cockpit", shell=True, universal_newlines=True)
|
||||
|
||||
if self.verbose:
|
||||
print("installed packages: {0}".format(packages))
|
||||
|
||||
installed_packages = packages.strip().split("\n")
|
||||
return installed_packages
|
||||
|
||||
def clean_network(self):
|
||||
if self.verbose:
|
||||
print("clean network configuration:")
|
||||
subprocess.check_call(["rm", "-rf", "/var/lib/NetworkManager"])
|
||||
subprocess.check_call(["rm", "-rf", "/var/lib/dhcp"])
|
||||
|
||||
def run(self):
|
||||
# Delete previous deployment if it's present
|
||||
output = subprocess.check_output(["ostree", "admin", "status"])
|
||||
if output.count(b"origin refspec") != 1:
|
||||
subprocess.check_call(["ostree", "admin", "undeploy", "1"])
|
||||
|
||||
self.setup_dirs()
|
||||
|
||||
installed_packages = self.get_installed_cockpit_packages()
|
||||
self.remove_packages(installed_packages)
|
||||
|
||||
packages_to_install = self.package_basenames(installed_packages)
|
||||
for p in self.packages_force_install:
|
||||
if not p in packages_to_install:
|
||||
if self.verbose:
|
||||
print("adding package %s (forced)" % (p))
|
||||
packages_to_install.append(p)
|
||||
|
||||
packages_to_install = list(filter(lambda p: any(os.path.split(p)[1].startswith(base) for base in packages_to_install), self.rpms))
|
||||
|
||||
if self.verbose:
|
||||
print("packages to install:")
|
||||
print(packages_to_install)
|
||||
|
||||
if self.external_packages:
|
||||
names = self.external_packages.keys()
|
||||
if self.verbose:
|
||||
print("external packages to install:")
|
||||
print(list(names))
|
||||
|
||||
downloader = URLopener()
|
||||
for name, url in self.external_packages.items():
|
||||
downloader.retrieve(url, name)
|
||||
|
||||
self.install_packages(names, replace=True)
|
||||
|
||||
for name in names:
|
||||
os.remove(name)
|
||||
|
||||
self.install_packages(packages_to_install)
|
||||
no_deps = [x for x in self.rpms \
|
||||
if os.path.split(x)[-1].startswith("cockpit-tests") or
|
||||
os.path.split(x)[-1].startswith("cockpit-machines")]
|
||||
self.install_packages(no_deps, deps=False, replace=True)
|
||||
|
||||
# If firewalld is installed, we need to poke a hole for cockpit, so
|
||||
# that we can run firewall tests on it (change firewall-cmd to
|
||||
# --add-service=cockpit once all supported atomics ship with the
|
||||
# service file)
|
||||
if subprocess.call(["systemctl", "enable", "--now", "firewalld"]) == 0:
|
||||
subprocess.call(["firewall-cmd", "--permanent", "--add-port=9090/tcp"])
|
||||
|
||||
self.commit_to_repo()
|
||||
self.switch_to_local_tree()
|
||||
self.update_container()
|
||||
self.clean_network()
|
||||
|
||||
parser = argparse.ArgumentParser(description='Install Cockpit in Atomic')
|
||||
parser.add_argument('-v', '--verbose', action='store_true', help='Display verbose progress details')
|
||||
parser.add_argument('-q', '--quick', action='store_true', help='Build faster')
|
||||
parser.add_argument('--build', action='store_true', help='Build')
|
||||
parser.add_argument('--install', action='store_true', help='Install')
|
||||
parser.add_argument('--extra', action='append', default=[], help='Extra packages to install inside the container')
|
||||
parser.add_argument('--skip', action='append', default=[], help='Packes to skip during installation')
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.build:
|
||||
sys.stderr.write("Can't build on Atomic\n")
|
||||
sys.exit(1)
|
||||
|
||||
if args.install:
|
||||
os.chdir("build-results")
|
||||
# Force skip cockpit-dashboard
|
||||
if args.skip:
|
||||
skip = list(args.skip)
|
||||
else:
|
||||
skip = []
|
||||
skip.append("cockpit-dashboard")
|
||||
|
||||
rpms = [os.path.abspath(f) for f in os.listdir(".")
|
||||
if (f.endswith(".rpm") and not f.endswith(".src.rpm")
|
||||
and not any(f.startswith(s) for s in args.skip))]
|
||||
cockpit_installer = AtomicCockpitInstaller(rpms=rpms, extra_rpms=args.extra, verbose=args.verbose)
|
||||
cockpit_installer.run()
|
||||
|
||||
# vim: ft=python
|
||||
Loading…
Add table
Add a link
Reference in a new issue