2018-12-27 15:15:08 +01:00
|
|
|
#!/usr/bin/env python3
|
2019-01-10 17:48:15 +01:00
|
|
|
|
2023-02-17 15:35:27 +02:00
|
|
|
# Copyright (C) 2018-2023 Internet Systems Consortium, Inc. ("ISC")
|
2019-01-10 17:48:15 +01:00
|
|
|
#
|
|
|
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
2022-03-10 09:58:39 +02:00
|
|
|
|
2019-01-29 12:07:09 +01:00
|
|
|
"""Hammer - Kea development environment management tool."""
|
2019-01-10 17:48:15 +01:00
|
|
|
|
2018-12-27 15:15:08 +01:00
|
|
|
from __future__ import print_function
|
2022-03-11 16:38:50 +02:00
|
|
|
|
2018-12-27 15:15:08 +01:00
|
|
|
import os
|
2022-09-05 19:19:09 +03:00
|
|
|
import random
|
2019-03-04 11:36:57 +01:00
|
|
|
import re
|
2018-12-27 15:15:08 +01:00
|
|
|
import sys
|
|
|
|
import glob
|
|
|
|
import time
|
2019-01-22 11:59:25 +01:00
|
|
|
import json
|
2018-12-27 15:15:08 +01:00
|
|
|
import logging
|
2019-01-10 17:36:02 +01:00
|
|
|
import datetime
|
2019-01-22 11:59:25 +01:00
|
|
|
import platform
|
|
|
|
import binascii
|
|
|
|
import argparse
|
2019-01-28 12:16:33 +01:00
|
|
|
import textwrap
|
|
|
|
import functools
|
2019-01-22 11:59:25 +01:00
|
|
|
import subprocess
|
2018-12-27 15:15:08 +01:00
|
|
|
import multiprocessing
|
2020-10-20 14:58:03 +02:00
|
|
|
import grp
|
|
|
|
import pwd
|
2021-02-16 11:50:25 +01:00
|
|
|
import getpass
|
2022-03-11 16:38:50 +02:00
|
|
|
|
2019-03-25 09:02:18 +01:00
|
|
|
try:
|
|
|
|
import urllib.request
|
|
|
|
except:
|
|
|
|
pass
|
2019-04-10 10:50:15 +02:00
|
|
|
try:
|
|
|
|
from urllib.parse import urljoin
|
|
|
|
except:
|
|
|
|
from urlparse import urljoin
|
2022-03-11 16:38:50 +02:00
|
|
|
|
2019-01-10 17:36:02 +01:00
|
|
|
import xml.etree.ElementTree as ET
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
|
|
|
|
SYSTEMS = {
|
2020-05-12 11:39:17 +02:00
|
|
|
'fedora': [
|
|
|
|
#'27', # EOLed
|
|
|
|
#'28', # EOLed
|
|
|
|
#'29', # EOLed
|
2021-06-07 14:52:51 +02:00
|
|
|
#'30', # EOLed
|
|
|
|
#'31', # EOLed
|
|
|
|
'32', # EOLed
|
2022-05-18 09:22:15 +02:00
|
|
|
'33', # EOLed
|
2021-06-07 14:52:51 +02:00
|
|
|
'34',
|
2022-05-18 09:22:15 +02:00
|
|
|
'35',
|
2023-06-20 16:07:57 +00:00
|
|
|
'36',
|
2023-06-20 22:20:25 +00:00
|
|
|
'37',
|
|
|
|
'38'
|
2021-06-07 14:52:51 +02:00
|
|
|
],
|
|
|
|
'centos': [
|
|
|
|
'7',
|
|
|
|
'8',
|
2022-07-29 09:51:10 +03:00
|
|
|
'9',
|
2021-06-07 14:52:51 +02:00
|
|
|
],
|
2022-05-18 09:22:15 +02:00
|
|
|
'rhel': [
|
2022-06-13 18:03:32 +02:00
|
|
|
'8',
|
|
|
|
'9',
|
2022-05-18 09:22:15 +02:00
|
|
|
],
|
2020-05-12 11:39:17 +02:00
|
|
|
'ubuntu': [
|
|
|
|
#'16.04',
|
|
|
|
'18.04',
|
|
|
|
#'18.10', # EOLed
|
|
|
|
#'19.04', # EOLed
|
2021-06-07 14:52:51 +02:00
|
|
|
#'19.10', # EOLed
|
2021-01-19 19:09:45 +01:00
|
|
|
'20.04',
|
2021-06-07 14:52:51 +02:00
|
|
|
'20.10',
|
|
|
|
'21.04',
|
2022-06-08 17:46:33 +02:00
|
|
|
'22.04',
|
2021-06-07 14:52:51 +02:00
|
|
|
],
|
|
|
|
'debian': [
|
|
|
|
#'8',
|
|
|
|
'9',
|
|
|
|
'10',
|
2023-06-15 13:23:44 +00:00
|
|
|
'11',
|
|
|
|
'12'
|
2021-06-07 14:52:51 +02:00
|
|
|
],
|
|
|
|
'freebsd': [
|
|
|
|
'11.2',
|
|
|
|
'11.4',
|
|
|
|
'12.0',
|
|
|
|
'12.1',
|
|
|
|
'13.0',
|
|
|
|
],
|
2020-05-15 07:36:04 +02:00
|
|
|
'alpine': [
|
2021-06-07 14:52:51 +02:00
|
|
|
#'3.10', # EOLed
|
2022-06-29 14:23:25 -07:00
|
|
|
#'3.11', # EOLed
|
|
|
|
#'3.12', # EOLed
|
2021-06-07 14:52:51 +02:00
|
|
|
'3.13',
|
2022-02-01 05:19:12 -08:00
|
|
|
'3.14',
|
|
|
|
'3.15',
|
2022-06-29 14:23:25 -07:00
|
|
|
'3.16',
|
2023-03-23 12:54:34 +00:00
|
|
|
'3.17',
|
2021-11-03 20:08:46 +02:00
|
|
|
],
|
|
|
|
'arch': []
|
2018-12-27 15:15:08 +01:00
|
|
|
}
|
|
|
|
|
2019-01-29 12:07:09 +01:00
|
|
|
# pylint: disable=C0326
|
2018-12-27 15:15:08 +01:00
|
|
|
IMAGE_TEMPLATES = {
|
2021-06-07 14:52:51 +02:00
|
|
|
# fedora
|
2019-01-10 17:36:02 +01:00
|
|
|
'fedora-27-lxc': {'bare': 'lxc-fedora-27', 'kea': 'godfryd/kea-fedora-27'},
|
|
|
|
'fedora-27-virtualbox': {'bare': 'generic/fedora27', 'kea': 'godfryd/kea-fedora-27'},
|
2019-04-14 07:26:50 +02:00
|
|
|
'fedora-28-lxc': {'bare': 'godfryd/lxc-fedora-28', 'kea': 'godfryd/kea-fedora-28'},
|
2019-01-10 17:36:02 +01:00
|
|
|
'fedora-28-virtualbox': {'bare': 'generic/fedora28', 'kea': 'godfryd/kea-fedora-28'},
|
|
|
|
'fedora-29-lxc': {'bare': 'godfryd/lxc-fedora-29', 'kea': 'godfryd/kea-fedora-29'},
|
|
|
|
'fedora-29-virtualbox': {'bare': 'generic/fedora29', 'kea': 'godfryd/kea-fedora-29'},
|
2019-05-14 08:11:34 +02:00
|
|
|
'fedora-30-lxc': {'bare': 'godfryd/lxc-fedora-30', 'kea': 'godfryd/kea-fedora-30'},
|
|
|
|
'fedora-30-virtualbox': {'bare': 'generic/fedora30', 'kea': 'godfryd/kea-fedora-30'},
|
2019-12-20 09:58:04 +01:00
|
|
|
'fedora-31-lxc': {'bare': 'isc/lxc-fedora-31', 'kea': 'isc/kea-fedora-31'},
|
|
|
|
'fedora-31-virtualbox': {'bare': 'isc/vbox-fedora-31', 'kea': 'isc/kea-fedora-31'},
|
2020-05-12 11:39:17 +02:00
|
|
|
'fedora-32-lxc': {'bare': 'isc/lxc-fedora-32', 'kea': 'isc/kea-fedora-32'},
|
2021-01-19 19:09:45 +01:00
|
|
|
'fedora-33-lxc': {'bare': 'isc/lxc-fedora-33', 'kea': 'isc/kea-fedora-33'},
|
2021-06-07 14:52:51 +02:00
|
|
|
'fedora-34-lxc': {'bare': 'isc/lxc-fedora-34', 'kea': 'isc/kea-fedora-34'},
|
2022-05-18 09:22:15 +02:00
|
|
|
'fedora-35-lxc': {'bare': 'isc/lxc-fedora-35', 'kea': 'isc/kea-fedora-35'},
|
|
|
|
'fedora-36-lxc': {'bare': 'isc/lxc-fedora-36', 'kea': 'isc/kea-fedora-36'},
|
2023-06-20 16:07:57 +00:00
|
|
|
'fedora-37-lxc': {'bare': 'isc/lxc-fedora-37', 'kea': 'isc/kea-fedora-37'},
|
2021-06-07 14:52:51 +02:00
|
|
|
|
|
|
|
# centos
|
2021-06-28 12:19:36 +02:00
|
|
|
'centos-7-lxc': {'bare': 'isc/lxc-centos-7', 'kea': 'isc/kea-centos-7'},
|
2019-01-10 17:36:02 +01:00
|
|
|
'centos-7-virtualbox': {'bare': 'generic/centos7', 'kea': 'godfryd/kea-centos-7'},
|
2019-10-14 22:59:54 +07:00
|
|
|
'centos-8-lxc': {'bare': 'isc/lxc-centos-8', 'kea': 'isc/kea-centos-8'},
|
|
|
|
'centos-8-virtualbox': {'bare': 'generic/centos8', 'kea': 'isc/kea-centos-8'},
|
2021-06-07 14:52:51 +02:00
|
|
|
|
|
|
|
# rhel
|
2018-12-27 15:15:08 +01:00
|
|
|
'rhel-8-virtualbox': {'bare': 'generic/rhel8', 'kea': 'generic/rhel8'},
|
2021-06-07 14:52:51 +02:00
|
|
|
|
|
|
|
# ubuntu
|
2019-01-10 17:36:02 +01:00
|
|
|
'ubuntu-16.04-lxc': {'bare': 'godfryd/lxc-ubuntu-16.04', 'kea': 'godfryd/kea-ubuntu-16.04'},
|
|
|
|
'ubuntu-16.04-virtualbox': {'bare': 'ubuntu/xenial64', 'kea': 'godfryd/kea-ubuntu-16.04'},
|
2021-06-28 12:19:36 +02:00
|
|
|
'ubuntu-18.04-lxc': {'bare': 'isc/lxc-ubuntu-18.04', 'kea': 'isc/kea-ubuntu-18.04'},
|
2019-01-10 17:36:02 +01:00
|
|
|
'ubuntu-18.04-virtualbox': {'bare': 'ubuntu/bionic64', 'kea': 'godfryd/kea-ubuntu-18.04'},
|
|
|
|
'ubuntu-18.10-lxc': {'bare': 'godfryd/lxc-ubuntu-18.10', 'kea': 'godfryd/kea-ubuntu-18.10'},
|
|
|
|
'ubuntu-18.10-virtualbox': {'bare': 'ubuntu/cosmic64', 'kea': 'godfryd/kea-ubuntu-18.10'},
|
2019-05-10 16:07:23 +02:00
|
|
|
'ubuntu-19.04-lxc': {'bare': 'godfryd/lxc-ubuntu-19.04', 'kea': 'godfryd/kea-ubuntu-19.04'},
|
|
|
|
'ubuntu-19.04-virtualbox': {'bare': 'ubuntu/disco64', 'kea': 'godfryd/kea-ubuntu-19.04'},
|
2019-12-20 09:58:04 +01:00
|
|
|
'ubuntu-19.10-lxc': {'bare': 'isc/lxc-ubuntu-19.10', 'kea': 'isc/kea-ubuntu-19.10'},
|
|
|
|
'ubuntu-19.10-virtualbox': {'bare': 'generic/ubuntu1910', 'kea': 'isc/kea-ubuntu-19.10'},
|
2020-05-12 11:39:17 +02:00
|
|
|
'ubuntu-20.04-lxc': {'bare': 'isc/lxc-ubuntu-20.04', 'kea': 'isc/kea-ubuntu-20.04'},
|
2021-01-19 19:09:45 +01:00
|
|
|
'ubuntu-20.10-lxc': {'bare': 'isc/lxc-ubuntu-20.10', 'kea': 'isc/kea-ubuntu-20.10'},
|
2021-06-07 14:52:51 +02:00
|
|
|
'ubuntu-21.04-lxc': {'bare': 'isc/lxc-ubuntu-21.04', 'kea': 'isc/kea-ubuntu-21.04'},
|
2022-06-08 17:46:33 +02:00
|
|
|
'ubuntu-22.04-lxc': {'bare': 'isc/lxc-ubuntu-22.04', 'kea': 'isc/lxc-ubuntu-22.04'},
|
2021-06-07 14:52:51 +02:00
|
|
|
|
|
|
|
# debian
|
2019-01-10 17:36:02 +01:00
|
|
|
'debian-8-lxc': {'bare': 'godfryd/lxc-debian-8', 'kea': 'godfryd/kea-debian-8'},
|
|
|
|
'debian-8-virtualbox': {'bare': 'debian/jessie64', 'kea': 'godfryd/kea-debian-8'},
|
2021-06-28 12:19:36 +02:00
|
|
|
'debian-9-lxc': {'bare': 'isc/lxc-debian-9', 'kea': 'isc/kea-debian-9'},
|
2019-01-10 17:36:02 +01:00
|
|
|
'debian-9-virtualbox': {'bare': 'debian/stretch64', 'kea': 'godfryd/kea-debian-9'},
|
2021-06-28 12:19:36 +02:00
|
|
|
'debian-10-lxc': {'bare': 'isc/lxc-debian-10', 'kea': 'isc/kea-debian-10'},
|
2019-06-24 21:58:48 +02:00
|
|
|
'debian-10-virtualbox': {'bare': 'debian/buster64', 'kea': 'godfryd/kea-debian-10'},
|
2021-11-12 01:07:13 +01:00
|
|
|
'debian-11-lxc': {'bare': 'isc/lxc-debian-11', 'kea': 'isc/kea-debian-11'},
|
2023-06-15 13:23:44 +00:00
|
|
|
'debian-12-lxc': {'bare': 'isc/lxc-debian-12', 'kea': 'isc/kea-debian-12'},
|
2021-06-07 14:52:51 +02:00
|
|
|
|
|
|
|
# freebsd
|
2019-01-10 17:36:02 +01:00
|
|
|
'freebsd-11.2-virtualbox': {'bare': 'generic/freebsd11', 'kea': 'godfryd/kea-freebsd-11.2'},
|
|
|
|
'freebsd-12.0-virtualbox': {'bare': 'generic/freebsd12', 'kea': 'godfryd/kea-freebsd-12.0'},
|
2021-06-07 14:52:51 +02:00
|
|
|
'freebsd-13.0-virtualbox': {'bare': 'isc/vbox-freebsd-13.0', 'kea': 'isc/kea-freebsd-13.0'},
|
|
|
|
|
|
|
|
# alpine
|
2019-09-26 15:20:05 +02:00
|
|
|
'alpine-3.10-lxc': {'bare': 'godfryd/lxc-alpine-3.10', 'kea': 'godfryd/kea-alpine-3.10'},
|
2020-05-15 07:36:04 +02:00
|
|
|
'alpine-3.11-lxc': {'bare': 'isc/lxc-alpine-3.11', 'kea': 'isc/kea-alpine-3.11'},
|
2020-09-23 17:50:08 +02:00
|
|
|
'alpine-3.12-lxc': {'bare': 'isc/lxc-alpine-3.12', 'kea': 'isc/kea-alpine-3.12'},
|
2021-06-07 14:52:51 +02:00
|
|
|
'alpine-3.13-lxc': {'bare': 'isc/lxc-alpine-3.13', 'kea': 'isc/kea-alpine-3.13'},
|
2022-02-01 05:19:12 -08:00
|
|
|
'alpine-3.14-lxc': {'bare': 'isc/lxc-alpine-3.14', 'kea': 'isc/kea-alpine-3.14'},
|
|
|
|
'alpine-3.15-lxc': {'bare': 'isc/lxc-alpine-3.15', 'kea': 'isc/kea-alpine-3.15'},
|
2022-06-29 14:23:25 -07:00
|
|
|
'alpine-3.16-lxc': {'bare': 'isc/lxc-alpine-3.16', 'kea': 'isc/kea-alpine-3.16'},
|
2023-03-23 12:54:34 +00:00
|
|
|
'alpine-3.17-lxc': {'bare': 'isc/lxc-alpine-3.17', 'kea': 'isc/kea-alpine-3.17'},
|
2018-12-27 15:15:08 +01:00
|
|
|
}
|
|
|
|
|
2020-05-15 07:36:04 +02:00
|
|
|
# NOTES
|
|
|
|
# ** Alpine **
|
|
|
|
# 1. Extracting rootfs is failing:
|
2021-03-18 10:22:04 +02:00
|
|
|
# It requires commenting out checking if rootfs has been extracted as it checks for file /bin/true which is a link.
|
2020-09-23 17:50:08 +02:00
|
|
|
# Comment out in ~/.vagrant.d/gems/2.X.Y/gems/vagrant-lxc-1.4.3/scripts/lxc-template near 'Failed to extract rootfs'
|
2020-05-15 07:36:04 +02:00
|
|
|
|
|
|
|
|
2018-12-27 15:15:08 +01:00
|
|
|
LXC_VAGRANTFILE_TPL = """# -*- mode: ruby -*-
|
|
|
|
# vi: set ft=ruby :
|
2019-03-25 09:02:18 +01:00
|
|
|
ENV["LC_ALL"] = "C"
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
Vagrant.configure("2") do |config|
|
2020-05-15 07:36:04 +02:00
|
|
|
{hostname}
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
config.vm.box = "{image_tpl}"
|
2019-03-25 09:02:18 +01:00
|
|
|
{box_version}
|
2019-01-10 17:36:02 +01:00
|
|
|
|
|
|
|
config.vm.provider "lxc" do |lxc|
|
|
|
|
lxc.container_name = "{name}"
|
2019-01-22 13:05:20 +01:00
|
|
|
lxc.customize 'rootfs.path', "/var/lib/lxc/{name}/rootfs"
|
2019-01-10 17:36:02 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
config.vm.synced_folder '.', '/vagrant', disabled: true
|
2019-03-14 16:37:12 +01:00
|
|
|
config.vm.synced_folder '{ccache_dir}', '/ccache'
|
2018-12-27 15:15:08 +01:00
|
|
|
end
|
|
|
|
"""
|
|
|
|
|
|
|
|
VBOX_VAGRANTFILE_TPL = """# -*- mode: ruby -*-
|
|
|
|
# vi: set ft=ruby :
|
2019-03-25 09:02:18 +01:00
|
|
|
ENV["LC_ALL"] = "C"
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
Vagrant.configure("2") do |config|
|
2019-01-10 17:36:02 +01:00
|
|
|
config.vm.hostname = "{name}"
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
config.vm.box = "{image_tpl}"
|
2019-03-25 09:02:18 +01:00
|
|
|
{box_version}
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
config.vm.provider "virtualbox" do |v|
|
2019-01-10 17:36:02 +01:00
|
|
|
v.name = "{name}"
|
2018-12-27 15:15:08 +01:00
|
|
|
v.memory = 8192
|
|
|
|
|
|
|
|
nproc = Etc.nprocessors
|
|
|
|
if nproc > 8
|
|
|
|
nproc -= 2
|
|
|
|
elsif nproc > 1
|
|
|
|
nproc -= 1
|
|
|
|
end
|
|
|
|
v.cpus = nproc
|
|
|
|
end
|
2019-01-10 17:36:02 +01:00
|
|
|
|
|
|
|
config.vm.synced_folder '.', '/vagrant', disabled: true
|
2018-12-27 15:15:08 +01:00
|
|
|
end
|
|
|
|
"""
|
|
|
|
|
2021-11-03 19:50:49 +02:00
|
|
|
RECOMMENDED_VAGRANT_VERSION='2.2.16'
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
log = logging.getLogger()
|
|
|
|
|
|
|
|
|
2019-01-10 17:36:02 +01:00
|
|
|
def red(txt):
|
2019-01-31 11:36:38 +01:00
|
|
|
"""Return colorized (if the terminal supports it) or plain text."""
|
2019-01-10 17:36:02 +01:00
|
|
|
if sys.stdout.isatty():
|
|
|
|
return '\033[1;31m%s\033[0;0m' % txt
|
2019-01-29 12:07:09 +01:00
|
|
|
return txt
|
2019-01-10 17:36:02 +01:00
|
|
|
|
|
|
|
def green(txt):
|
2019-01-31 11:36:38 +01:00
|
|
|
"""Return colorized (if the terminal supports it) or plain text."""
|
2019-01-10 17:36:02 +01:00
|
|
|
if sys.stdout.isatty():
|
|
|
|
return '\033[0;32m%s\033[0;0m' % txt
|
2019-01-29 12:07:09 +01:00
|
|
|
return txt
|
2019-01-10 17:36:02 +01:00
|
|
|
|
|
|
|
def blue(txt):
|
2019-01-31 11:36:38 +01:00
|
|
|
"""Return colorized (if the terminal supports it) or plain text."""
|
2019-01-10 17:36:02 +01:00
|
|
|
if sys.stdout.isatty():
|
|
|
|
return '\033[0;34m%s\033[0;0m' % txt
|
2019-01-29 12:07:09 +01:00
|
|
|
return txt
|
2019-01-10 17:36:02 +01:00
|
|
|
|
|
|
|
|
2018-12-27 15:15:08 +01:00
|
|
|
def get_system_revision():
|
2019-01-29 11:30:05 +01:00
|
|
|
"""Return tuple containing system name and its revision."""
|
2018-12-27 15:15:08 +01:00
|
|
|
system = platform.system()
|
|
|
|
if system == 'Linux':
|
2020-05-12 11:39:17 +02:00
|
|
|
system, revision = None, None
|
|
|
|
try:
|
|
|
|
system, revision, _ = platform.dist() # pylint: disable=deprecated-method
|
|
|
|
if system == 'debian':
|
|
|
|
revision = revision.split('.')[0]
|
|
|
|
elif system == 'redhat':
|
|
|
|
system = 'rhel'
|
|
|
|
revision = revision[0]
|
|
|
|
elif system == 'centos':
|
|
|
|
revision = revision[0]
|
2020-05-15 07:36:04 +02:00
|
|
|
if not system or not revision:
|
|
|
|
raise Exception('fallback to /etc/os-release')
|
2020-05-12 11:39:17 +02:00
|
|
|
except:
|
2019-09-26 15:20:05 +02:00
|
|
|
if os.path.exists('/etc/os-release'):
|
|
|
|
vals = {}
|
|
|
|
with open('/etc/os-release') as f:
|
|
|
|
for l in f.readlines():
|
|
|
|
if '=' in l:
|
|
|
|
key, val = l.split('=', 1)
|
2022-06-13 18:03:32 +02:00
|
|
|
vals[key.strip()] = val.strip().replace('"', '')
|
2021-11-03 20:08:46 +02:00
|
|
|
|
|
|
|
for i in ['ID', 'ID_LIKE']:
|
2022-07-29 09:51:10 +03:00
|
|
|
if i in vals:
|
|
|
|
system_candidate=vals[i].strip('"')
|
|
|
|
if system_candidate in SYSTEMS:
|
|
|
|
system = system_candidate
|
|
|
|
break
|
2021-11-03 20:08:46 +02:00
|
|
|
if system is None:
|
|
|
|
raise Exception('cannot determine system')
|
|
|
|
|
|
|
|
for i in ['VERSION_ID', 'BUILD_ID']:
|
|
|
|
if i in vals:
|
|
|
|
revision = vals[i]
|
|
|
|
break
|
|
|
|
if revision is None:
|
|
|
|
raise Exception('cannot determine revision')
|
|
|
|
|
2022-06-13 18:03:32 +02:00
|
|
|
if system in ['alpine', 'rhel']:
|
2019-09-26 15:20:05 +02:00
|
|
|
revision = revision.rsplit('.', 1)[0]
|
2020-05-12 11:39:17 +02:00
|
|
|
else:
|
|
|
|
raise Exception('cannot determine system or its revision')
|
2018-12-27 15:15:08 +01:00
|
|
|
elif system == 'FreeBSD':
|
|
|
|
system = system.lower()
|
|
|
|
revision = platform.release()
|
2019-12-20 09:58:04 +01:00
|
|
|
if '"' in revision:
|
|
|
|
revision = revision.replace('"', '')
|
2020-12-03 00:14:40 +01:00
|
|
|
if '"' in system:
|
|
|
|
system = system.replace('"', '')
|
2021-11-03 20:08:46 +02:00
|
|
|
|
|
|
|
system = system.lower()
|
|
|
|
return system, revision
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
|
2019-01-29 12:07:09 +01:00
|
|
|
class ExecutionError(Exception):
|
2019-01-30 20:44:35 +01:00
|
|
|
"""Exception thrown when execution encountered an error."""
|
2019-01-29 12:07:09 +01:00
|
|
|
pass
|
|
|
|
|
2019-01-10 17:36:02 +01:00
|
|
|
|
2019-01-31 11:36:38 +01:00
|
|
|
def execute(cmd, timeout=60, cwd=None, env=None, raise_error=True, dry_run=False, log_file_path=None,
|
|
|
|
quiet=False, check_times=False, capture=False, interactive=False, attempts=1,
|
2021-01-05 10:12:00 +01:00
|
|
|
sleep_time_after_attempt=None, super_quiet=False):
|
2019-01-29 11:30:05 +01:00
|
|
|
"""Execute a command in shell.
|
|
|
|
|
|
|
|
:param str cmd: a command to be executed
|
2019-01-31 11:36:38 +01:00
|
|
|
:param int timeout: timeout in number of seconds, after that time the command is terminated
|
|
|
|
but only if check_times is True
|
2019-01-29 11:30:05 +01:00
|
|
|
:param str cwd: current working directory for the command
|
|
|
|
:param dict env: dictionary with environment variables
|
2019-01-31 11:36:38 +01:00
|
|
|
:param bool raise_error: if False then in case of error exception is not raised,
|
|
|
|
default: True ie exception is raise
|
2019-01-29 11:30:05 +01:00
|
|
|
:param bool dry_run: if True then the command is not executed
|
|
|
|
:param str log_file_path: if provided then all traces from the command are stored in indicated file
|
|
|
|
:param bool quiet: if True then the command's traces are not printed to stdout
|
|
|
|
:param bool check_times: if True then timeout is taken into account
|
|
|
|
:param bool capture: if True then the command's traces are captured and returned by the function
|
2019-01-31 11:36:38 +01:00
|
|
|
:param bool interactive: if True then stdin and stdout are not redirected, traces handling is disabled,
|
|
|
|
used for e.g. SSH
|
2020-05-29 15:25:16 +02:00
|
|
|
:param int attempts: number of attempts to run the command if it fails
|
2019-01-29 14:46:07 +01:00
|
|
|
:param int sleep_time_after_attempt: number of seconds to sleep before taking next attempt
|
2022-09-05 19:32:22 +03:00
|
|
|
:param bool super_quiet: if True, set quiet to True and don't log command
|
2019-01-29 11:30:05 +01:00
|
|
|
"""
|
2021-01-05 10:12:00 +01:00
|
|
|
if super_quiet:
|
|
|
|
quiet = True
|
2022-11-30 12:29:34 +01:00
|
|
|
if cwd and "~/" in cwd:
|
|
|
|
# replace relative home directory
|
2023-01-25 22:38:59 +02:00
|
|
|
cwd = cwd.replace('~', os.environ['HOME'])
|
2022-11-30 12:42:10 +01:00
|
|
|
if not super_quiet:
|
|
|
|
log.info('>>>>> Executing %s in %s', cmd, cwd if cwd else os.getcwd())
|
2019-01-10 17:36:02 +01:00
|
|
|
if not check_times:
|
|
|
|
timeout = None
|
|
|
|
if dry_run:
|
|
|
|
return 0
|
2019-01-25 16:08:12 +01:00
|
|
|
|
2019-01-29 14:46:07 +01:00
|
|
|
if 'sudo' in cmd and env:
|
|
|
|
# if sudo is used and env is overridden then to preserve env add -E to sudo
|
|
|
|
cmd = cmd.replace('sudo', 'sudo -E')
|
2019-01-29 11:30:05 +01:00
|
|
|
|
2019-01-29 14:46:07 +01:00
|
|
|
if log_file_path:
|
|
|
|
log_file = open(log_file_path, "wb")
|
2019-01-25 16:08:12 +01:00
|
|
|
|
2019-01-29 14:46:07 +01:00
|
|
|
for attempt in range(attempts):
|
|
|
|
if interactive:
|
|
|
|
p = subprocess.Popen(cmd, cwd=cwd, env=env, shell=True)
|
|
|
|
exitcode = p.wait()
|
2019-01-10 17:36:02 +01:00
|
|
|
|
2019-01-29 14:46:07 +01:00
|
|
|
else:
|
|
|
|
p = subprocess.Popen(cmd, cwd=cwd, env=env, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
2019-01-10 17:36:02 +01:00
|
|
|
|
2019-01-29 14:46:07 +01:00
|
|
|
if capture:
|
|
|
|
output = ''
|
|
|
|
t0 = time.time()
|
2021-01-22 01:36:41 +02:00
|
|
|
# repeat until process is running or timeout not occurred
|
2023-01-26 00:12:05 +02:00
|
|
|
while True:
|
2019-01-29 14:46:07 +01:00
|
|
|
line = p.stdout.readline()
|
|
|
|
if line:
|
2021-04-19 15:41:40 +03:00
|
|
|
line_decoded = line.decode(encoding='ascii', errors='ignore').rstrip() + '\r'
|
2019-01-29 14:46:07 +01:00
|
|
|
if not quiet:
|
2022-09-05 19:32:22 +03:00
|
|
|
log.info(line_decoded)
|
2019-01-29 14:46:07 +01:00
|
|
|
if capture:
|
|
|
|
output += line_decoded
|
|
|
|
if log_file_path:
|
|
|
|
log_file.write(line)
|
|
|
|
t1 = time.time()
|
2023-01-26 00:12:05 +02:00
|
|
|
if p.poll() is not None or (timeout is not None and timeout < t1 - t0):
|
|
|
|
break
|
2019-01-29 14:46:07 +01:00
|
|
|
|
2021-01-22 01:36:41 +02:00
|
|
|
# If no exitcode yet, ie. process is still running then it means that timeout occurred.
|
2019-01-29 14:46:07 +01:00
|
|
|
# In such case terminate the process and raise an exception.
|
|
|
|
if p.poll() is None:
|
2019-01-31 11:36:38 +01:00
|
|
|
# kill using sudo to be able to kill other sudo commands
|
|
|
|
execute('sudo kill -s TERM %s' % p.pid)
|
|
|
|
time.sleep(5)
|
|
|
|
# if still running, kill harder
|
|
|
|
if p.poll() is None:
|
|
|
|
execute('sudo kill -s KILL %s' % p.pid)
|
2019-02-19 14:37:00 +01:00
|
|
|
msg = "Execution timeout, %d > %d seconds elapsed (start: %d, stop %d), cmd: '%s'"
|
|
|
|
msg = msg % (t1 - t0, timeout, t0, t1, cmd)
|
|
|
|
raise ExecutionError(msg)
|
2019-01-29 14:46:07 +01:00
|
|
|
exitcode = p.returncode
|
|
|
|
|
|
|
|
if exitcode == 0:
|
|
|
|
break
|
|
|
|
elif attempt < attempts - 1:
|
|
|
|
txt = 'command failed, retry, attempt %d/%d' % (attempt, attempts)
|
|
|
|
if log_file_path:
|
|
|
|
txt_to_file = '\n\n[HAMMER] %s\n\n\n' % txt
|
|
|
|
log_file.write(txt_to_file.encode('ascii'))
|
|
|
|
log.info(txt)
|
|
|
|
if sleep_time_after_attempt:
|
|
|
|
time.sleep(sleep_time_after_attempt)
|
|
|
|
|
|
|
|
if log_file_path:
|
|
|
|
log_file.close()
|
2019-01-10 17:36:02 +01:00
|
|
|
|
2018-12-27 15:15:08 +01:00
|
|
|
if exitcode != 0 and raise_error:
|
2019-03-25 09:02:18 +01:00
|
|
|
if capture and quiet:
|
|
|
|
log.error(output)
|
2019-01-10 17:36:02 +01:00
|
|
|
raise ExecutionError("The command return non-zero exitcode %s, cmd: '%s'" % (exitcode, cmd))
|
2019-01-25 16:08:12 +01:00
|
|
|
|
|
|
|
if capture:
|
|
|
|
return exitcode, output
|
2019-01-29 12:07:09 +01:00
|
|
|
return exitcode
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
|
2022-07-26 22:01:31 +03:00
|
|
|
def _append_to_file(file_name, line):
|
|
|
|
with open(file_name, encoding='utf-8', mode='a') as f:
|
|
|
|
f.write(line + '\n')
|
|
|
|
|
|
|
|
|
2019-03-25 09:02:18 +01:00
|
|
|
def _prepare_installed_packages_cache_for_debs():
|
|
|
|
pkg_cache = {}
|
|
|
|
|
|
|
|
_, out = execute("dpkg -l", timeout=15, capture=True, quiet=True)
|
|
|
|
|
|
|
|
for line in out.splitlines():
|
|
|
|
line = line.strip()
|
|
|
|
m = re.search('^([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+(.+)', line)
|
|
|
|
if not m:
|
|
|
|
continue
|
|
|
|
status, name, version, arch, descr = m.groups()
|
|
|
|
name = name.split(':')[0]
|
|
|
|
pkg_cache[name] = dict(status=status, version=version, arch=arch, descr=descr)
|
|
|
|
|
|
|
|
return pkg_cache
|
|
|
|
|
|
|
|
|
|
|
|
def _prepare_installed_packages_cache_for_rpms():
|
|
|
|
pkg_cache = {}
|
|
|
|
|
|
|
|
_, out = execute("rpm -qa --qf '%{NAME}\\n'", timeout=15, capture=True, quiet=True)
|
|
|
|
|
|
|
|
for line in out.splitlines():
|
|
|
|
name = line.strip()
|
|
|
|
pkg_cache[name] = dict(status='ii')
|
|
|
|
|
|
|
|
return pkg_cache
|
|
|
|
|
|
|
|
|
2019-09-26 15:20:05 +02:00
|
|
|
def _prepare_installed_packages_cache_for_alpine():
|
|
|
|
pkg_cache = {}
|
|
|
|
|
|
|
|
_, out = execute("apk list -I\\n'", timeout=15, capture=True, quiet=True)
|
|
|
|
|
|
|
|
for line in out.splitlines():
|
|
|
|
name = line.strip()
|
|
|
|
pkg_cache[name] = dict(status='ii')
|
|
|
|
|
|
|
|
return pkg_cache
|
|
|
|
|
|
|
|
|
2022-03-11 16:38:50 +02:00
|
|
|
def install_pkgs(pkgs, timeout=60, env=None, check_times=False, pkg_cache=None):
|
2019-01-31 11:36:38 +01:00
|
|
|
"""Install native packages in a system.
|
2019-01-30 20:44:35 +01:00
|
|
|
|
|
|
|
:param dict pkgs: specifies a list of packages to be installed
|
|
|
|
:param int timeout: timeout in number of seconds, after that time the command
|
|
|
|
is terminated but only if check_times is True
|
|
|
|
:param dict env: dictionary with environment variables (optional)
|
|
|
|
:param bool check_times: specifies if timeouts should be enabled (optional)
|
|
|
|
"""
|
2019-01-29 14:46:07 +01:00
|
|
|
system, revision = get_system_revision()
|
|
|
|
|
2019-03-25 09:02:18 +01:00
|
|
|
if not isinstance(pkgs, list):
|
|
|
|
pkgs = pkgs.split()
|
|
|
|
|
2022-03-11 16:38:50 +02:00
|
|
|
if pkg_cache is None:
|
|
|
|
pkg_cache = {}
|
|
|
|
|
2019-03-25 09:02:18 +01:00
|
|
|
# prepare cache if needed
|
2019-09-26 15:20:05 +02:00
|
|
|
if not pkg_cache and system in ['centos', 'rhel', 'fedora', 'debian', 'ubuntu']:#, 'alpine']: # TODO: complete caching support for alpine
|
2019-03-25 09:02:18 +01:00
|
|
|
if system in ['centos', 'rhel', 'fedora']:
|
|
|
|
pkg_cache.update(_prepare_installed_packages_cache_for_rpms())
|
|
|
|
elif system in ['debian', 'ubuntu']:
|
|
|
|
pkg_cache.update(_prepare_installed_packages_cache_for_debs())
|
2019-09-26 15:20:05 +02:00
|
|
|
elif system in ['alpine']:
|
|
|
|
pkg_cache.update(_prepare_installed_packages_cache_for_alpine())
|
2019-03-25 09:02:18 +01:00
|
|
|
|
2019-04-10 10:50:15 +02:00
|
|
|
# check if packages actually need to be installed
|
|
|
|
if pkg_cache:
|
2019-03-25 09:02:18 +01:00
|
|
|
pkgs_to_install = []
|
2021-04-15 10:28:04 +02:00
|
|
|
pkgs_installed = []
|
2019-03-25 09:02:18 +01:00
|
|
|
for pkg in pkgs:
|
|
|
|
if pkg not in pkg_cache or pkg_cache[pkg]['status'] != 'ii':
|
|
|
|
pkgs_to_install.append(pkg)
|
2021-04-15 10:28:04 +02:00
|
|
|
else:
|
|
|
|
pkgs_installed.append(pkg)
|
|
|
|
if pkgs_installed:
|
|
|
|
log.info('packages already installed: %s', ', '.join(pkgs_installed))
|
2019-03-25 09:02:18 +01:00
|
|
|
pkgs = pkgs_to_install
|
|
|
|
|
|
|
|
if not pkgs:
|
|
|
|
log.info('all packages already installed')
|
|
|
|
return
|
|
|
|
|
2022-09-05 22:30:17 +03:00
|
|
|
if system in ['centos', 'fedora', 'rhel']:
|
|
|
|
if system in ['centos', 'rhel'] and revision == '7':
|
|
|
|
execute('sudo yum install -y dnf')
|
2019-01-29 14:46:07 +01:00
|
|
|
cmd = 'sudo dnf -y install'
|
|
|
|
elif system in ['debian', 'ubuntu']:
|
2019-03-25 09:02:18 +01:00
|
|
|
# prepare the command for ubuntu/debian
|
2019-01-29 14:46:07 +01:00
|
|
|
if not env:
|
|
|
|
env = os.environ.copy()
|
|
|
|
env['DEBIAN_FRONTEND'] = 'noninteractive'
|
|
|
|
cmd = 'sudo apt install --no-install-recommends -y'
|
|
|
|
elif system == 'freebsd':
|
|
|
|
cmd = 'sudo pkg install -y'
|
2019-09-26 15:20:05 +02:00
|
|
|
elif system == 'alpine':
|
|
|
|
cmd = 'sudo apk add'
|
2021-11-03 20:08:46 +02:00
|
|
|
elif system == 'arch':
|
|
|
|
cmd = 'sudo pacman -S --needed --noconfirm --overwrite \'*\''
|
2019-03-25 09:02:18 +01:00
|
|
|
else:
|
2019-09-26 15:20:05 +02:00
|
|
|
raise NotImplementedError('no implementation for %s' % system)
|
2019-01-29 14:46:07 +01:00
|
|
|
|
2019-03-25 09:02:18 +01:00
|
|
|
pkgs = ' '.join(pkgs)
|
2019-01-29 14:46:07 +01:00
|
|
|
cmd += ' ' + pkgs
|
|
|
|
execute(cmd, timeout=timeout, env=env, check_times=check_times, attempts=3, sleep_time_after_attempt=10)
|
2019-01-10 17:36:02 +01:00
|
|
|
|
|
|
|
|
2021-11-03 18:03:03 +02:00
|
|
|
def get_image_template(key, variant):
|
|
|
|
if key not in IMAGE_TEMPLATES:
|
2021-11-19 19:17:36 +02:00
|
|
|
print('ERROR: Image {} is not available.'.format(key), file=sys.stderr)
|
2021-11-03 18:03:03 +02:00
|
|
|
sys.exit(1)
|
|
|
|
if variant not in IMAGE_TEMPLATES[key]:
|
2021-11-19 19:17:36 +02:00
|
|
|
print('ERROR: Variant {} is not available for image {}.'.format(variant, key), file=sys.stderr)
|
2021-11-03 18:03:03 +02:00
|
|
|
sys.exit(1)
|
|
|
|
return IMAGE_TEMPLATES[key][variant]
|
|
|
|
|
|
|
|
|
2019-04-10 10:50:15 +02:00
|
|
|
def _get_full_repo_url(repository_url, system, revision, pkg_version):
|
|
|
|
if not repository_url:
|
|
|
|
return None
|
|
|
|
repo_name = 'kea-%s-%s-%s' % (pkg_version.rsplit('.', 1)[0], system, revision)
|
|
|
|
repo_url = urljoin(repository_url, 'repository')
|
|
|
|
repo_url += '/%s-ci/' % repo_name
|
|
|
|
return repo_url
|
|
|
|
|
|
|
|
|
2018-12-27 15:15:08 +01:00
|
|
|
class VagrantEnv(object):
|
2019-01-29 11:30:05 +01:00
|
|
|
"""Helper class that makes interacting with Vagrant easier.
|
|
|
|
|
|
|
|
It creates Vagrantfile according to specified system. It exposes basic Vagrant functions
|
2021-03-18 10:22:04 +02:00
|
|
|
like up, upload, destroy, ssh. It also provides more complex function for preparing system
|
2019-01-29 11:30:05 +01:00
|
|
|
for Kea build and building Kea.
|
|
|
|
"""
|
|
|
|
|
2019-01-31 11:36:38 +01:00
|
|
|
def __init__(self, provider, system, revision, features, image_template_variant,
|
2019-03-14 16:37:12 +01:00
|
|
|
dry_run, quiet=False, check_times=False, ccache_dir=None):
|
2019-01-31 11:36:38 +01:00
|
|
|
"""VagrantEnv initializer.
|
|
|
|
|
|
|
|
:param str provider: indicate backend type: virtualbox or lxc
|
|
|
|
:param str system: name of the system eg. ubuntu
|
|
|
|
:param str revision: revision of the system e.g. 18.04
|
|
|
|
:param list features: list of requested features
|
|
|
|
:param str image_template_variant: variant of images' templates: bare or kea
|
|
|
|
:param bool dry_run: if False then system commands are not really executed
|
|
|
|
:param bool quiet: if True then commands will not trace to stdout
|
|
|
|
:param bool check_times: if True then commands will be terminated after given timeout
|
|
|
|
"""
|
2019-01-10 17:36:02 +01:00
|
|
|
self.provider = provider
|
2018-12-27 15:15:08 +01:00
|
|
|
self.system = system
|
2019-01-31 11:36:38 +01:00
|
|
|
self.revision = revision
|
2018-12-27 15:15:08 +01:00
|
|
|
self.features = features
|
2019-01-10 17:36:02 +01:00
|
|
|
self.dry_run = dry_run
|
|
|
|
self.quiet = quiet
|
|
|
|
self.check_times = check_times
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-01-29 12:07:09 +01:00
|
|
|
# set properly later
|
|
|
|
self.features_arg = None
|
|
|
|
self.nofeatures_arg = None
|
|
|
|
self.python = None
|
|
|
|
|
2019-03-25 09:02:18 +01:00
|
|
|
self.key = key = "%s-%s-%s" % (system, revision, provider)
|
2021-11-03 18:03:03 +02:00
|
|
|
self.image_tpl = image_tpl = get_image_template(key, image_template_variant)
|
2018-12-27 15:15:08 +01:00
|
|
|
self.repo_dir = os.getcwd()
|
|
|
|
|
2019-01-31 11:36:38 +01:00
|
|
|
sys_dir = "%s-%s" % (system, revision)
|
2018-12-27 15:15:08 +01:00
|
|
|
if provider == "virtualbox":
|
2019-01-10 17:36:02 +01:00
|
|
|
self.vagrant_dir = os.path.join(self.repo_dir, 'hammer', sys_dir, 'vbox')
|
2018-12-27 15:15:08 +01:00
|
|
|
elif provider == "lxc":
|
2019-01-10 17:36:02 +01:00
|
|
|
self.vagrant_dir = os.path.join(self.repo_dir, 'hammer', sys_dir, 'lxc')
|
|
|
|
|
2021-06-07 14:52:51 +02:00
|
|
|
if ccache_dir is None:
|
|
|
|
self.ccache_dir = '/'
|
|
|
|
self.ccache_enabled = False
|
|
|
|
else:
|
|
|
|
self.ccache_dir = ccache_dir
|
|
|
|
self.ccache_enabled = True
|
|
|
|
|
|
|
|
self.init_files()
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2021-06-07 14:52:51 +02:00
|
|
|
def init_files(self):
|
2019-01-10 17:36:02 +01:00
|
|
|
if not os.path.exists(self.vagrant_dir):
|
|
|
|
os.makedirs(self.vagrant_dir)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-01-10 17:36:02 +01:00
|
|
|
vagrantfile_path = os.path.join(self.vagrant_dir, "Vagrantfile")
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-01-22 11:59:25 +01:00
|
|
|
crc = binascii.crc32(self.vagrant_dir.encode())
|
2021-06-07 14:52:51 +02:00
|
|
|
self.name = "hmr-%s-%s-kea-srv-%08d" % (self.system, self.revision.replace('.', '-'), crc)
|
2019-03-14 16:37:12 +01:00
|
|
|
|
2021-06-07 14:52:51 +02:00
|
|
|
if '/' in self.image_tpl:
|
2019-03-25 09:02:18 +01:00
|
|
|
self.latest_version = self._get_latest_cloud_version()
|
|
|
|
box_version = 'config.vm.box_version = "%s"' % self.latest_version
|
|
|
|
else:
|
|
|
|
self.latest_version = None
|
|
|
|
box_version = ""
|
|
|
|
|
2020-05-15 07:36:04 +02:00
|
|
|
# alpine has a problem with setting hostname so skip it
|
2021-06-07 14:52:51 +02:00
|
|
|
if self.system == 'alpine':
|
2020-05-15 07:36:04 +02:00
|
|
|
hostname = ''
|
|
|
|
else:
|
|
|
|
hostname = 'config.vm.hostname = "%s"' % self.name
|
|
|
|
|
2021-06-07 14:52:51 +02:00
|
|
|
if self.provider == "virtualbox":
|
|
|
|
vagrantfile_tpl = VBOX_VAGRANTFILE_TPL
|
|
|
|
elif self.provider == "lxc":
|
|
|
|
vagrantfile_tpl = LXC_VAGRANTFILE_TPL
|
|
|
|
|
|
|
|
vagrantfile = vagrantfile_tpl.format(image_tpl=self.image_tpl,
|
2019-03-14 16:37:12 +01:00
|
|
|
name=self.name,
|
2021-06-07 14:52:51 +02:00
|
|
|
ccache_dir=self.ccache_dir,
|
2020-05-15 07:36:04 +02:00
|
|
|
box_version=box_version,
|
|
|
|
hostname=hostname)
|
2019-01-22 11:59:25 +01:00
|
|
|
|
2018-12-27 15:15:08 +01:00
|
|
|
with open(vagrantfile_path, "w") as f:
|
|
|
|
f.write(vagrantfile)
|
|
|
|
|
2019-01-22 11:59:25 +01:00
|
|
|
log.info('Prepared vagrant system %s in %s', self.name, self.vagrant_dir)
|
|
|
|
|
2018-12-27 15:15:08 +01:00
|
|
|
def up(self):
|
2019-01-31 11:36:38 +01:00
|
|
|
"""Do Vagrant up."""
|
2019-04-14 07:26:50 +02:00
|
|
|
exitcode, out = execute("vagrant up --no-provision --provider %s" % self.provider,
|
|
|
|
cwd=self.vagrant_dir, timeout=15 * 60, dry_run=self.dry_run,
|
|
|
|
capture=True, raise_error=False)
|
|
|
|
if exitcode != 0:
|
|
|
|
if 'There is container on your system' in out and 'lxc-destroy' in out:
|
|
|
|
m = re.search('`lxc-destroy.*?`', out)
|
|
|
|
if m:
|
|
|
|
# destroy some old container
|
|
|
|
cmd = m.group(0)[1:-1]
|
|
|
|
cmd = 'sudo ' + cmd + ' -f'
|
|
|
|
execute(cmd, timeout=60)
|
|
|
|
|
|
|
|
# try again spinning up new
|
|
|
|
execute("vagrant up --no-provision --provider %s" % self.provider,
|
|
|
|
cwd=self.vagrant_dir, timeout=15 * 60, dry_run=self.dry_run)
|
|
|
|
return
|
|
|
|
raise ExecutionError('There is a problem with putting up a system')
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-03-25 09:02:18 +01:00
|
|
|
def _get_cloud_meta(self, image_tpl=None):
|
|
|
|
if '/' not in self.image_tpl:
|
|
|
|
return {}
|
|
|
|
url = 'https://app.vagrantup.com/api/v1/box/' + (image_tpl if image_tpl else self.image_tpl)
|
|
|
|
try:
|
|
|
|
with urllib.request.urlopen(url) as response:
|
|
|
|
data = response.read()
|
|
|
|
except:
|
|
|
|
log.exception('ignored exception')
|
|
|
|
return {}
|
|
|
|
data = json.loads(data)
|
|
|
|
return data
|
|
|
|
|
|
|
|
def _get_local_meta(self):
|
|
|
|
meta_file = os.path.join(self.vagrant_dir, '.vagrant/machines/default', self.provider, 'box_meta')
|
|
|
|
if not os.path.exists(meta_file):
|
|
|
|
return {}
|
|
|
|
with open(meta_file) as f:
|
|
|
|
data = f.read()
|
|
|
|
data = json.loads(data)
|
|
|
|
return data
|
|
|
|
|
|
|
|
def _get_latest_cloud_version(self, image_tpl=None):
|
|
|
|
cloud_meta = self._get_cloud_meta(image_tpl)
|
|
|
|
if not cloud_meta and 'versions' not in cloud_meta:
|
|
|
|
return 0
|
|
|
|
latest_version = 0
|
|
|
|
for ver in cloud_meta['versions']:
|
|
|
|
provider_found = False
|
|
|
|
for p in ver['providers']:
|
|
|
|
if p['name'] == self.provider:
|
|
|
|
provider_found = True
|
|
|
|
break
|
|
|
|
if provider_found:
|
2019-05-14 08:11:34 +02:00
|
|
|
try:
|
|
|
|
v = int(ver['number'])
|
|
|
|
except:
|
|
|
|
return ver['number']
|
2019-03-25 09:02:18 +01:00
|
|
|
if v > latest_version:
|
|
|
|
latest_version = v
|
|
|
|
return latest_version
|
|
|
|
|
|
|
|
def get_status(self):
|
|
|
|
"""Return system status.
|
|
|
|
|
|
|
|
Status can be: 'not created', 'running', 'stopped', etc.
|
|
|
|
"""
|
2021-06-07 14:52:51 +02:00
|
|
|
if not os.path.exists(self.vagrant_dir):
|
|
|
|
return "not created"
|
|
|
|
|
2019-03-25 09:02:18 +01:00
|
|
|
_, out = execute("vagrant status", cwd=self.vagrant_dir, timeout=15, capture=True, quiet=True)
|
|
|
|
m = re.search('default\s+(.+)\(', out)
|
|
|
|
if not m:
|
|
|
|
raise Exception('cannot get status in:\n%s' % out)
|
|
|
|
return m.group(1).strip()
|
|
|
|
|
|
|
|
def bring_up_latest_box(self):
|
|
|
|
if self.get_status() == 'running':
|
|
|
|
self.reload()
|
|
|
|
else:
|
|
|
|
self.up()
|
|
|
|
|
|
|
|
def reload(self):
|
|
|
|
"""Do Vagrant reload."""
|
|
|
|
execute("vagrant reload --no-provision --force",
|
|
|
|
cwd=self.vagrant_dir, timeout=15 * 60, dry_run=self.dry_run)
|
|
|
|
|
|
|
|
|
2018-12-27 15:15:08 +01:00
|
|
|
def package(self):
|
2019-01-29 11:30:05 +01:00
|
|
|
"""Package Vagrant system into Vagrant box."""
|
2021-03-15 09:54:46 +01:00
|
|
|
execute('vagrant halt', cwd=self.vagrant_dir, dry_run=self.dry_run, raise_error=False, attempts=3)
|
2019-01-29 11:30:05 +01:00
|
|
|
|
2019-06-24 21:58:48 +02:00
|
|
|
box_path = os.path.join(self.vagrant_dir, 'kea-%s-%s.box' % (self.system, self.revision))
|
|
|
|
if os.path.exists(box_path):
|
|
|
|
os.unlink(box_path)
|
2019-05-10 16:07:23 +02:00
|
|
|
|
2019-06-24 21:58:48 +02:00
|
|
|
if self.provider == 'virtualbox':
|
2019-03-25 09:02:18 +01:00
|
|
|
cmd = "vagrant package --output %s" % box_path
|
2019-01-10 17:36:02 +01:00
|
|
|
execute(cmd, cwd=self.vagrant_dir, timeout=4 * 60, dry_run=self.dry_run)
|
|
|
|
|
|
|
|
elif self.provider == 'lxc':
|
|
|
|
lxc_box_dir = os.path.join(self.vagrant_dir, 'lxc-box')
|
|
|
|
if os.path.exists(lxc_box_dir):
|
|
|
|
execute('sudo rm -rf %s' % lxc_box_dir)
|
|
|
|
os.mkdir(lxc_box_dir)
|
|
|
|
lxc_container_path = os.path.join('/var/lib/lxc', self.name)
|
2021-03-15 09:54:46 +01:00
|
|
|
|
|
|
|
# add vagrant universal key to accepted keys
|
2019-01-31 11:36:38 +01:00
|
|
|
execute('sudo bash -c \'echo "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8ia'
|
|
|
|
'llvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ'
|
|
|
|
'6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTB'
|
|
|
|
'ckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6k'
|
|
|
|
'ivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmB'
|
|
|
|
'YSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYC'
|
|
|
|
'zRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key"'
|
|
|
|
'> %s/rootfs/home/vagrant/.ssh/authorized_keys\'' % lxc_container_path)
|
2021-03-15 09:54:46 +01:00
|
|
|
|
|
|
|
# reset machine-id
|
|
|
|
execute('sudo rm -f %s/rootfs/var/lib/dbus/machine-id' % lxc_container_path)
|
|
|
|
#execute('sudo truncate -s 0 %s/rootfs/etc/machine-id' % lxc_container_path)
|
|
|
|
execute('sudo rm -f %s/rootfs/etc/machine-id' % lxc_container_path)
|
|
|
|
|
|
|
|
# pack rootfs
|
2019-01-31 11:36:38 +01:00
|
|
|
cmd = 'sudo bash -c "'
|
|
|
|
cmd += 'cd %s '
|
|
|
|
cmd += '&& tar --numeric-owner --anchored --exclude=./rootfs/dev/log -czf %s/rootfs.tar.gz ./rootfs/*'
|
|
|
|
cmd += '"'
|
2019-01-29 12:07:09 +01:00
|
|
|
execute(cmd % (lxc_container_path, lxc_box_dir))
|
2021-03-15 09:54:46 +01:00
|
|
|
|
|
|
|
# copy lxc config from runtime container
|
2019-01-10 17:36:02 +01:00
|
|
|
execute('sudo cp %s/config %s/lxc-config' % (lxc_container_path, lxc_box_dir))
|
2021-03-15 09:54:46 +01:00
|
|
|
# remove mac address from eth0 - it should be dynamically assigned
|
|
|
|
execute("sudo sed -i '/lxc.net.0.hwaddr/d' %s/lxc-config" % lxc_box_dir)
|
|
|
|
# correct files ownership
|
2019-01-10 17:36:02 +01:00
|
|
|
execute('sudo chown `id -un`:`id -gn` *', cwd=lxc_box_dir)
|
2021-03-15 09:54:46 +01:00
|
|
|
# and other metadata
|
2019-01-10 17:36:02 +01:00
|
|
|
with open(os.path.join(lxc_box_dir, 'metadata.json'), 'w') as f:
|
|
|
|
now = datetime.datetime.now()
|
|
|
|
f.write('{\n')
|
|
|
|
f.write(' "provider": "lxc",\n')
|
|
|
|
f.write(' "version": "1.0.0",\n')
|
|
|
|
f.write(' "built-on": "%s"\n' % now.strftime('%c'))
|
|
|
|
f.write('}\n')
|
|
|
|
|
2021-03-15 09:54:46 +01:00
|
|
|
# pack vagrant box with metadata and config
|
2019-01-10 17:36:02 +01:00
|
|
|
execute('tar -czf %s ./*' % box_path, cwd=lxc_box_dir)
|
|
|
|
execute('sudo rm -rf %s' % lxc_box_dir)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-03-25 09:02:18 +01:00
|
|
|
return box_path
|
|
|
|
|
|
|
|
def upload_to_cloud(self, box_path):
|
2021-11-03 18:03:03 +02:00
|
|
|
image_tpl = get_image_template(self.key, 'kea')
|
2019-03-25 09:02:18 +01:00
|
|
|
if '/' not in image_tpl:
|
|
|
|
return
|
|
|
|
|
|
|
|
latest_version = self._get_latest_cloud_version(image_tpl)
|
|
|
|
new_version = latest_version + 1
|
|
|
|
|
2021-06-07 14:52:51 +02:00
|
|
|
cmd = "vagrant cloud publish --no-private -f -r %s %s %s %s"
|
2019-03-25 09:02:18 +01:00
|
|
|
cmd = cmd % (image_tpl, new_version, self.provider, box_path)
|
|
|
|
|
|
|
|
execute(cmd, cwd=self.vagrant_dir, timeout=60 * 60)
|
|
|
|
|
2019-01-24 15:32:03 +01:00
|
|
|
def upload(self, src):
|
2019-01-29 12:07:09 +01:00
|
|
|
"""Upload src to Vagrant system, home folder."""
|
2019-01-24 15:32:03 +01:00
|
|
|
attempt = 4
|
|
|
|
while attempt > 0:
|
|
|
|
exitcode = execute('vagrant upload %s' % src, cwd=self.vagrant_dir, dry_run=self.dry_run, raise_error=False)
|
|
|
|
if exitcode == 0:
|
|
|
|
break
|
|
|
|
attempt -= 1
|
|
|
|
if exitcode != 0:
|
|
|
|
msg = 'cannot upload %s' % src
|
|
|
|
log.error(msg)
|
|
|
|
raise ExecutionError(msg)
|
|
|
|
|
2019-04-10 10:50:15 +02:00
|
|
|
def run_build_and_test(self, tarball_path, jobs, pkg_version, pkg_isc_version, upload, repository_url):
|
2019-01-29 11:30:05 +01:00
|
|
|
"""Run build and unit tests inside Vagrant system."""
|
2019-01-10 17:36:02 +01:00
|
|
|
if self.dry_run:
|
|
|
|
return 0, 0
|
|
|
|
|
2019-01-29 11:30:05 +01:00
|
|
|
# prepare tarball if needed and upload it to vagrant system
|
2018-12-27 15:15:08 +01:00
|
|
|
if not tarball_path:
|
2022-11-29 20:59:19 +02:00
|
|
|
execute('mkdir -p ~/.hammer-tmp')
|
2019-04-10 10:50:15 +02:00
|
|
|
name_ver = 'kea-%s' % pkg_version
|
2019-01-17 16:41:03 +01:00
|
|
|
cmd = 'tar --transform "flags=r;s|^|%s/|" --exclude hammer ' % name_ver
|
2019-01-31 11:36:38 +01:00
|
|
|
cmd += ' --exclude "*~" --exclude .git --exclude .libs '
|
|
|
|
cmd += ' --exclude .deps --exclude \'*.o\' --exclude \'*.lo\' '
|
2022-11-29 20:59:19 +02:00
|
|
|
cmd += ' -zcf ~/.hammer-tmp/%s.tar.gz .' % name_ver
|
2019-01-17 16:41:03 +01:00
|
|
|
execute(cmd)
|
2022-11-29 20:59:19 +02:00
|
|
|
tarball_path = '~/.hammer-tmp/%s.tar.gz' % name_ver
|
2019-01-24 15:32:03 +01:00
|
|
|
self.upload(tarball_path)
|
2022-11-29 20:59:19 +02:00
|
|
|
execute('rm -rf ~/.hammer-tmp')
|
2019-01-10 17:36:02 +01:00
|
|
|
|
|
|
|
log_file_path = os.path.join(self.vagrant_dir, 'build.log')
|
|
|
|
log.info('Build log file stored to %s', log_file_path)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
t0 = time.time()
|
2019-01-10 17:36:02 +01:00
|
|
|
|
2019-01-29 11:30:05 +01:00
|
|
|
# run build command
|
2019-04-10 10:50:15 +02:00
|
|
|
bld_cmd = "{python} hammer.py build -p local {features} {nofeatures} {check_times} {ccache}"
|
|
|
|
bld_cmd += " {tarball} {jobs} {pkg_version} {pkg_isc_version} {repository_url}"
|
|
|
|
bld_cmd = bld_cmd.format(python=self.python,
|
|
|
|
features=self.features_arg,
|
|
|
|
nofeatures=self.nofeatures_arg,
|
|
|
|
check_times='-i' if self.check_times else '',
|
|
|
|
ccache='--ccache-dir /ccache' if self.ccache_enabled else '',
|
2021-04-15 10:28:04 +02:00
|
|
|
tarball='-t ~/%s.tar.gz' % name_ver,
|
2019-04-10 10:50:15 +02:00
|
|
|
jobs='-j %d' % jobs,
|
|
|
|
pkg_version='--pkg-version %s' % pkg_version,
|
|
|
|
pkg_isc_version='--pkg-isc-version %s' % pkg_isc_version,
|
|
|
|
repository_url=('--repository-url %s' % repository_url) if repository_url else '')
|
|
|
|
|
2019-01-30 18:11:18 +01:00
|
|
|
timeout = _calculate_build_timeout(self.features) + 5 * 60
|
2021-02-16 11:50:25 +01:00
|
|
|
# executes hammer.py inside LXC container
|
2019-01-30 18:11:18 +01:00
|
|
|
self.execute(bld_cmd, timeout=timeout, log_file_path=log_file_path, quiet=self.quiet) # timeout: 40 minutes
|
2019-01-10 17:36:02 +01:00
|
|
|
|
|
|
|
ssh_cfg_path = self.dump_ssh_config()
|
|
|
|
|
|
|
|
if 'native-pkg' in self.features:
|
2019-04-10 10:50:15 +02:00
|
|
|
pkgs_dir = os.path.join(self.vagrant_dir, 'pkgs')
|
|
|
|
if os.path.exists(pkgs_dir):
|
|
|
|
execute('rm -rf %s' % pkgs_dir)
|
|
|
|
os.makedirs(pkgs_dir)
|
|
|
|
|
2021-02-16 11:50:25 +01:00
|
|
|
# copy results of _build_native_pkg
|
2021-05-17 08:57:57 +02:00
|
|
|
execute('scp -F %s -r default:~/kea-pkg/* .' % ssh_cfg_path, cwd=pkgs_dir)
|
2019-04-10 10:50:15 +02:00
|
|
|
|
|
|
|
if upload:
|
|
|
|
repo_url = _get_full_repo_url(repository_url, self.system, self.revision, pkg_version)
|
|
|
|
assert repo_url is not None
|
|
|
|
upload_cmd = 'curl -v --netrc -f'
|
|
|
|
|
|
|
|
if self.system in ['ubuntu', 'debian']:
|
|
|
|
upload_cmd += ' -X POST -H "Content-Type: multipart/form-data" --data-binary "@%s" '
|
2023-03-29 11:01:10 +00:00
|
|
|
file_ext = 'deb' # include both '.deb' and '.ddeb' files
|
2019-04-10 10:50:15 +02:00
|
|
|
|
|
|
|
elif self.system in ['fedora', 'centos', 'rhel']:
|
|
|
|
upload_cmd += ' --upload-file %s '
|
|
|
|
file_ext = '.rpm'
|
|
|
|
|
2019-09-26 15:20:05 +02:00
|
|
|
elif self.system == 'alpine':
|
|
|
|
upload_cmd += ' --upload-file %s '
|
|
|
|
file_ext = ''
|
|
|
|
repo_url = urljoin(repo_url, '%s/v%s/x86_64/' % (pkg_isc_version, self.revision))
|
|
|
|
|
2019-04-10 10:50:15 +02:00
|
|
|
upload_cmd += ' ' + repo_url
|
|
|
|
|
|
|
|
for fn in os.listdir(pkgs_dir):
|
2019-09-26 15:20:05 +02:00
|
|
|
if file_ext and not fn.endswith(file_ext):
|
2019-04-10 10:50:15 +02:00
|
|
|
continue
|
|
|
|
fp = os.path.join(pkgs_dir, fn)
|
|
|
|
cmd = upload_cmd % fp
|
|
|
|
execute(cmd)
|
2019-01-10 17:36:02 +01:00
|
|
|
|
2018-12-27 15:15:08 +01:00
|
|
|
t1 = time.time()
|
|
|
|
dt = int(t1 - t0)
|
2019-01-10 17:36:02 +01:00
|
|
|
|
|
|
|
log.info('Build log file stored to %s', log_file_path)
|
2018-12-27 15:15:08 +01:00
|
|
|
log.info("")
|
|
|
|
log.info(">>>>>> Build time %s:%s", dt // 60, dt % 60)
|
|
|
|
log.info("")
|
|
|
|
|
2019-01-29 11:30:05 +01:00
|
|
|
# run unit tests if requested
|
2019-01-10 17:36:02 +01:00
|
|
|
total = 0
|
|
|
|
passed = 0
|
|
|
|
try:
|
|
|
|
if 'unittest' in self.features:
|
2019-01-31 11:36:38 +01:00
|
|
|
cmd = 'scp -F %s -r default:/home/vagrant/unit-test-results.json .' % ssh_cfg_path
|
|
|
|
execute(cmd, cwd=self.vagrant_dir)
|
2019-01-10 17:36:02 +01:00
|
|
|
results_file = os.path.join(self.vagrant_dir, 'unit-test-results.json')
|
|
|
|
if os.path.exists(results_file):
|
|
|
|
with open(results_file) as f:
|
|
|
|
txt = f.read()
|
|
|
|
results = json.loads(txt)
|
|
|
|
total = results['grand_total']
|
|
|
|
passed = results['grand_passed']
|
2019-03-25 09:02:18 +01:00
|
|
|
|
|
|
|
cmd = 'scp -F %s -r default:/home/vagrant/aggregated_tests.xml .' % ssh_cfg_path
|
|
|
|
execute(cmd, cwd=self.vagrant_dir)
|
2019-01-29 12:07:09 +01:00
|
|
|
except: # pylint: disable=bare-except
|
2019-01-10 17:36:02 +01:00
|
|
|
log.exception('ignored issue with parsing unit test results')
|
|
|
|
|
|
|
|
return total, passed
|
|
|
|
|
2019-01-25 16:08:12 +01:00
|
|
|
def destroy(self):
|
2019-01-31 11:36:38 +01:00
|
|
|
"""Remove the VM completely."""
|
2021-06-07 14:52:51 +02:00
|
|
|
if os.path.exists(self.vagrant_dir):
|
|
|
|
cmd = 'vagrant destroy --force'
|
|
|
|
execute(cmd, cwd=self.vagrant_dir, timeout=3 * 60, dry_run=self.dry_run) # timeout: 3 minutes
|
|
|
|
execute('rm -rf %s' % self.vagrant_dir)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
def ssh(self):
|
2019-01-30 20:44:35 +01:00
|
|
|
"""Open interactive session to the VM."""
|
2019-01-25 16:08:12 +01:00
|
|
|
execute('vagrant ssh', cwd=self.vagrant_dir, timeout=None, dry_run=self.dry_run, interactive=True)
|
2019-01-10 17:36:02 +01:00
|
|
|
|
|
|
|
def dump_ssh_config(self):
|
2019-01-29 11:30:05 +01:00
|
|
|
"""Dump ssh config that allows getting into Vagrant system via SSH."""
|
2019-01-10 17:36:02 +01:00
|
|
|
ssh_cfg_path = os.path.join(self.vagrant_dir, 'ssh.cfg')
|
|
|
|
execute('vagrant ssh-config > %s' % ssh_cfg_path, cwd=self.vagrant_dir)
|
|
|
|
return ssh_cfg_path
|
|
|
|
|
2020-09-25 10:12:35 +02:00
|
|
|
def execute(self, cmd, timeout=None, raise_error=True, log_file_path=None, quiet=False, env=None,
|
|
|
|
attempts=1, sleep_time_after_attempt=None):
|
2019-01-29 11:30:05 +01:00
|
|
|
"""Execute provided command inside Vagrant system."""
|
2019-01-10 17:36:02 +01:00
|
|
|
if not env:
|
|
|
|
env = os.environ.copy()
|
|
|
|
env['LANGUAGE'] = env['LANG'] = env['LC_ALL'] = 'C'
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-01-31 11:36:38 +01:00
|
|
|
return execute('vagrant ssh -c "%s"' % cmd, env=env, cwd=self.vagrant_dir, timeout=timeout,
|
|
|
|
raise_error=raise_error, dry_run=self.dry_run, log_file_path=log_file_path,
|
2020-09-25 10:12:35 +02:00
|
|
|
quiet=quiet, check_times=self.check_times,
|
|
|
|
attempts=attempts, sleep_time_after_attempt=sleep_time_after_attempt)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-01-25 16:08:12 +01:00
|
|
|
def prepare_system(self):
|
2019-01-29 11:30:05 +01:00
|
|
|
"""Prepare Vagrant system for building Kea."""
|
2019-01-10 17:36:02 +01:00
|
|
|
if self.features:
|
|
|
|
self.features_arg = '--with ' + ' '.join(self.features)
|
2018-12-27 15:15:08 +01:00
|
|
|
else:
|
|
|
|
self.features_arg = ''
|
|
|
|
|
2019-01-10 17:36:02 +01:00
|
|
|
nofeatures = set(DEFAULT_FEATURES) - self.features
|
2018-12-27 15:15:08 +01:00
|
|
|
if nofeatures:
|
|
|
|
self.nofeatures_arg = '--without ' + ' '.join(nofeatures)
|
|
|
|
else:
|
|
|
|
self.nofeatures_arg = ''
|
|
|
|
|
2021-06-07 14:52:51 +02:00
|
|
|
# install python3 on some systems
|
2021-05-20 08:16:01 +02:00
|
|
|
if self.system == 'centos':
|
|
|
|
if self.revision == '7':
|
|
|
|
self.execute("sudo yum remove -y python-devel")
|
|
|
|
self.execute("sudo yum install -y python36 rpm-build python3-virtualenv", attempts=3)
|
|
|
|
else:
|
|
|
|
self.execute("sudo dnf install -y python36 rpm-build python3-virtualenv", attempts=3)
|
2021-06-07 14:52:51 +02:00
|
|
|
elif self.system == 'freebsd':
|
|
|
|
if self.revision.startswith('13'):
|
|
|
|
self.execute("sudo pkg install -y python3", attempts=3)
|
2019-10-14 19:03:46 +07:00
|
|
|
|
2019-01-29 11:30:05 +01:00
|
|
|
# select proper python version for running Hammer inside Vagrant system
|
2021-05-20 08:16:01 +02:00
|
|
|
if self.system == 'freebsd':
|
2021-06-07 14:52:51 +02:00
|
|
|
if self.revision.startswith(('11', '12')):
|
|
|
|
self.python = 'python3.6'
|
|
|
|
else:
|
|
|
|
self.python = 'python3'
|
2018-12-27 15:15:08 +01:00
|
|
|
else:
|
|
|
|
self.python = 'python3'
|
|
|
|
|
2019-01-29 11:30:05 +01:00
|
|
|
# to get python in RHEL 8 beta it is required first register machine in RHEL account
|
2019-01-31 11:36:38 +01:00
|
|
|
if self.system == 'rhel' and self.revision == '8':
|
|
|
|
cmd = "sudo subscription-manager repos --list-enabled | grep rhel-8-for-x86_64-baseos-beta-rpms"
|
|
|
|
exitcode = self.execute(cmd, raise_error=False)
|
2018-12-27 15:15:08 +01:00
|
|
|
if exitcode != 0:
|
2019-01-10 17:36:02 +01:00
|
|
|
env = os.environ.copy()
|
|
|
|
with open(os.path.expanduser('~/rhel-creds.txt')) as f:
|
|
|
|
env['RHEL_USER'] = f.readline().strip()
|
|
|
|
env['RHEL_PASSWD'] = f.readline().strip()
|
|
|
|
self.execute('sudo subscription-manager register --user $RHEL_USER --password "$RHEL_PASSWD"', env=env)
|
2018-12-27 15:15:08 +01:00
|
|
|
self.execute("sudo subscription-manager refresh")
|
|
|
|
self.execute("sudo subscription-manager attach --pool 8a85f99a67cdc3e70167e45c85f47429")
|
|
|
|
self.execute("sudo subscription-manager repos --enable rhel-8-for-x86_64-baseos-beta-rpms")
|
|
|
|
self.execute("sudo dnf install -y python36")
|
|
|
|
|
2022-09-05 22:30:32 +03:00
|
|
|
# RPM-based distributions install libraries in /usr/local/lib64, but they
|
|
|
|
# tend to not look there at runtime without explicit mention in ld.so.conf.d.
|
|
|
|
if self.system in ['centos', 'fedora', 'rhel']:
|
|
|
|
self.execute('sudo echo /usr/local/lib64 > /etc/ld.so.conf.d/kea.conf')
|
|
|
|
# ldconfig only in case the change above was not there before system startup
|
|
|
|
self.execute('sudo ldconfig')
|
|
|
|
|
2019-01-29 11:30:05 +01:00
|
|
|
# upload Hammer to Vagrant system
|
2018-12-27 15:15:08 +01:00
|
|
|
hmr_py_path = os.path.join(self.repo_dir, 'hammer.py')
|
2019-01-24 15:32:03 +01:00
|
|
|
self.upload(hmr_py_path)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-01-10 17:36:02 +01:00
|
|
|
log_file_path = os.path.join(self.vagrant_dir, 'prepare.log')
|
|
|
|
log.info('Prepare log file stored to %s', log_file_path)
|
|
|
|
|
2019-03-25 09:02:18 +01:00
|
|
|
t0 = time.time()
|
|
|
|
|
2019-01-29 11:30:05 +01:00
|
|
|
# run prepare-system inside Vagrant system
|
2019-03-14 16:37:12 +01:00
|
|
|
cmd = "{python} hammer.py prepare-system -p local {features} {nofeatures} {check_times} {ccache}"
|
2019-04-10 10:50:15 +02:00
|
|
|
cmd = cmd.format(python=self.python,
|
|
|
|
features=self.features_arg,
|
2018-12-27 15:15:08 +01:00
|
|
|
nofeatures=self.nofeatures_arg,
|
2019-03-14 16:37:12 +01:00
|
|
|
check_times='-i' if self.check_times else '',
|
|
|
|
ccache='--ccache-dir /ccache' if self.ccache_enabled else '')
|
2019-01-10 17:36:02 +01:00
|
|
|
self.execute(cmd, timeout=40 * 60, log_file_path=log_file_path, quiet=self.quiet)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-03-25 09:02:18 +01:00
|
|
|
t1 = time.time()
|
|
|
|
dt = int(t1 - t0)
|
|
|
|
|
|
|
|
log.info('')
|
|
|
|
log.info(">>> Preparing %s, %s, %s completed in %s:%s", self.provider, self.system, self.revision,
|
|
|
|
dt // 60, dt % 60)
|
|
|
|
log.info('')
|
|
|
|
|
2021-03-15 09:54:46 +01:00
|
|
|
def prepare_for_boxing(self):
|
2021-06-07 14:52:51 +02:00
|
|
|
if self.system in ['debian', 'ubuntu', 'fedora', 'centos', 'rhel']:
|
|
|
|
# setup a script that on first boot will set machine-id
|
|
|
|
cmd = 'bash -c \'cat <<EOF | sudo tee /usr/lib/systemd/system/systemd-firstboot.service\n'
|
|
|
|
cmd += '[Unit]\n'
|
|
|
|
cmd += 'Description=Generate New Machine ID\n'
|
|
|
|
cmd += 'Documentation=man:systemd-firstboot(1)\n'
|
|
|
|
cmd += 'DefaultDependencies=no\n'
|
|
|
|
cmd += 'Conflicts=shutdown.target\n'
|
|
|
|
cmd += 'After=systemd-remount-fs.service\n'
|
|
|
|
cmd += 'Before=systemd-sysusers.service sysinit.target shutdown.target\n'
|
|
|
|
cmd += 'ConditionPathIsReadWrite=/etc\n'
|
|
|
|
cmd += 'ConditionFirstBoot=yes\n'
|
|
|
|
cmd += '[Service]\n'
|
|
|
|
cmd += 'Type=oneshot\n'
|
|
|
|
cmd += 'RemainAfterExit=yes\n'
|
|
|
|
cmd += 'ExecStart=/usr/bin/systemd-firstboot --setup-machine-id\n'
|
|
|
|
cmd += '[Install]\n'
|
|
|
|
cmd += 'WantedBy=sysinit.target\n'
|
|
|
|
cmd += "EOF\n\'"
|
|
|
|
self.execute(cmd)
|
|
|
|
self.execute('sudo systemctl enable systemd-firstboot.service')
|
|
|
|
|
|
|
|
elif self.system == 'freebsd':
|
|
|
|
self.execute('sudo pkg clean -a -y')
|
|
|
|
self.execute('sudo rm -rf /usr/lib/debug')
|
2021-03-15 09:54:46 +01:00
|
|
|
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
def _install_gtest_sources():
|
2019-01-30 20:44:35 +01:00
|
|
|
"""Install gtest sources."""
|
2019-01-29 11:30:05 +01:00
|
|
|
# download gtest sources only if it is not present as native package
|
2022-09-05 19:32:22 +03:00
|
|
|
gtest_version = '1.10.0'
|
|
|
|
gtest_path = f'/usr/src/googletest-release-{gtest_version}/googletest'
|
|
|
|
if os.path.exists(gtest_path):
|
|
|
|
log.info(f'gtest is already installed in {gtest_path}.')
|
|
|
|
return
|
|
|
|
|
2022-11-29 20:59:19 +02:00
|
|
|
execute('mkdir -p ~/.hammer-tmp')
|
|
|
|
cmd = 'wget --no-verbose -O ~/.hammer-tmp/gtest.tar.gz '
|
2022-09-05 19:32:22 +03:00
|
|
|
cmd += f'https://github.com/google/googletest/archive/release-{gtest_version}.tar.gz'
|
|
|
|
execute(cmd)
|
|
|
|
execute('sudo mkdir -p /usr/src')
|
2022-11-29 20:59:19 +02:00
|
|
|
execute('sudo tar -C /usr/src -zxf ~/.hammer-tmp/gtest.tar.gz')
|
2022-09-05 19:32:22 +03:00
|
|
|
execute(f'sudo ln -sf /usr/src/googletest-release-{gtest_version} /usr/src/googletest')
|
2022-11-29 20:59:19 +02:00
|
|
|
execute('rm -rf ~/.hammer-tmp')
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
|
2022-10-07 15:27:08 +03:00
|
|
|
def _install_libyang_from_sources(ignore_errors = False):
|
2021-08-05 18:12:10 +03:00
|
|
|
"""Install libyang from sources."""
|
|
|
|
for prefix in ['/usr', '/usr/local']:
|
2022-10-07 15:27:08 +03:00
|
|
|
libyang_so = f'{prefix}/lib/libyang.so'
|
|
|
|
libyang_header = f'{prefix}/include/libyang/version.h'
|
|
|
|
if (os.path.exists(libyang_so) and os.path.exists(libyang_header) and
|
|
|
|
execute(f"grep -F '#define LY_VERSION_MAJOR 2' '{libyang_header}'", raise_error=False) == 0):
|
|
|
|
log.info(f'libyang is already installed at {libyang_so}.')
|
2021-08-05 18:12:10 +03:00
|
|
|
return
|
|
|
|
|
2022-11-09 10:51:43 +02:00
|
|
|
version='v2.1.4'
|
2022-10-07 15:27:08 +03:00
|
|
|
|
2022-11-29 20:59:19 +02:00
|
|
|
execute('rm -rf ~/.hammer-tmp')
|
|
|
|
execute('mkdir -p ~/.hammer-tmp')
|
2021-08-05 18:12:10 +03:00
|
|
|
try:
|
2022-11-29 20:59:19 +02:00
|
|
|
execute('git clone https://github.com/CESNET/libyang.git ~/.hammer-tmp/libyang')
|
|
|
|
execute(f'git checkout {version}', cwd='~/.hammer-tmp/libyang')
|
|
|
|
execute('mkdir ~/.hammer-tmp/libyang/build')
|
|
|
|
execute('cmake ..', cwd='~/.hammer-tmp/libyang/build')
|
|
|
|
execute('make -j $(nproc || gnproc || echo 1)', cwd='~/.hammer-tmp/libyang/build')
|
|
|
|
execute('sudo make install', cwd='~/.hammer-tmp/libyang/build')
|
2022-10-07 15:27:08 +03:00
|
|
|
system, revision = get_system_revision()
|
|
|
|
if system != 'alpine':
|
|
|
|
execute('sudo ldconfig')
|
|
|
|
except Exception as e:
|
|
|
|
log.exception(str(e))
|
|
|
|
if not ignore_errors:
|
|
|
|
raise e
|
2021-08-05 18:12:10 +03:00
|
|
|
finally:
|
2022-11-29 20:59:19 +02:00
|
|
|
execute('rm -rf ~/.hammer-tmp')
|
2021-08-05 18:12:10 +03:00
|
|
|
|
|
|
|
|
2022-10-07 15:27:08 +03:00
|
|
|
def _install_sysrepo_from_sources(ignore_errors = False):
|
2021-08-05 18:12:10 +03:00
|
|
|
"""Install sysrepo from sources."""
|
|
|
|
for prefix in ['/usr', '/usr/local']:
|
2023-01-25 16:23:53 +02:00
|
|
|
sysrepo_so = f'{prefix}/lib/libsysrepo.so'
|
2022-11-08 12:12:53 +02:00
|
|
|
sysrepo_header = f'{prefix}/include/sysrepo/version.h'
|
2022-10-07 15:27:08 +03:00
|
|
|
if (os.path.exists(sysrepo_so) and os.path.exists(sysrepo_header) and
|
|
|
|
execute(f"grep -F '#define SR_VERSION_MAJOR 7' '{sysrepo_header}'", raise_error=False) == 0):
|
|
|
|
log.info(f'sysrepo is already installed at {sysrepo_so}.')
|
2021-08-05 18:12:10 +03:00
|
|
|
return
|
|
|
|
|
2022-11-09 10:51:43 +02:00
|
|
|
version='v2.2.12'
|
2021-08-05 18:12:10 +03:00
|
|
|
|
2021-09-18 10:10:01 +03:00
|
|
|
# Create repository for YANG modules and change ownership to current user.
|
|
|
|
execute('sudo mkdir -p /etc/sysrepo')
|
2021-11-10 21:04:19 +02:00
|
|
|
execute('sudo chown -R "${USER}:$(id -gn)" /etc/sysrepo')
|
2021-09-18 10:10:01 +03:00
|
|
|
|
2022-11-29 20:59:19 +02:00
|
|
|
execute('rm -rf ~/.hammer-tmp')
|
|
|
|
execute('mkdir -p ~/.hammer-tmp')
|
2021-08-05 18:12:10 +03:00
|
|
|
try:
|
2022-11-29 20:59:19 +02:00
|
|
|
execute('git clone https://github.com/sysrepo/sysrepo.git ~/.hammer-tmp/sysrepo')
|
|
|
|
execute(f'git checkout {version}', cwd='~/.hammer-tmp/sysrepo')
|
|
|
|
execute('mkdir ~/.hammer-tmp/sysrepo/build')
|
|
|
|
execute('cmake -DREPO_PATH=/etc/sysrepo ..', cwd='~/.hammer-tmp/sysrepo/build')
|
|
|
|
execute('make -j $(nproc || gnproc || echo 1)', cwd='~/.hammer-tmp/sysrepo/build')
|
|
|
|
execute('sudo make install', cwd='~/.hammer-tmp/sysrepo/build')
|
2022-10-07 15:27:08 +03:00
|
|
|
system, revision = get_system_revision()
|
|
|
|
if system != 'alpine':
|
|
|
|
execute('sudo ldconfig')
|
|
|
|
except Exception as e:
|
|
|
|
log.exception(str(e))
|
|
|
|
if not ignore_errors:
|
|
|
|
raise e
|
2021-08-05 18:12:10 +03:00
|
|
|
finally:
|
2022-11-29 20:59:19 +02:00
|
|
|
execute('rm -rf ~/.hammer-tmp')
|
2021-08-05 18:12:10 +03:00
|
|
|
|
|
|
|
|
2022-10-07 15:27:08 +03:00
|
|
|
def _install_libyang_cpp_from_sources(ignore_errors = False):
|
|
|
|
"""Install libyang-cpp from sources."""
|
|
|
|
for prefix in ['/usr', '/usr/local']:
|
|
|
|
libyang_cpp_so = f'{prefix}/lib/libyang-cpp.so'
|
|
|
|
libyang_cpp_pc = f'{prefix}/lib/pkgconfig/libyang-cpp.pc'
|
|
|
|
if (os.path.exists(libyang_cpp_so) and os.path.exists(libyang_cpp_pc) and
|
|
|
|
execute(f"grep -F 'Version: 1.1.0' '{libyang_cpp_pc}'", raise_error=False) == 0):
|
|
|
|
log.info(f'libyang-cpp is already installed at {libyang_cpp_so}.')
|
|
|
|
return
|
|
|
|
|
2022-11-09 10:51:43 +02:00
|
|
|
version='ae7d649ea75da081725c119dd553b2ef3121a6f8'
|
2022-10-07 15:27:08 +03:00
|
|
|
|
2022-11-29 20:59:19 +02:00
|
|
|
execute('rm -rf ~/.hammer-tmp')
|
|
|
|
execute('mkdir -p ~/.hammer-tmp')
|
2022-10-07 15:27:08 +03:00
|
|
|
try:
|
2022-11-29 20:59:19 +02:00
|
|
|
execute('git clone https://github.com/CESNET/libyang-cpp.git ~/.hammer-tmp/libyang-cpp')
|
|
|
|
execute(f'git checkout {version}', cwd='~/.hammer-tmp/libyang-cpp')
|
|
|
|
execute('mkdir ~/.hammer-tmp/libyang-cpp/build')
|
|
|
|
execute('cmake -DBUILD_TESTING=OFF .. ', cwd='~/.hammer-tmp/libyang-cpp/build')
|
|
|
|
execute('make -j $(nproc || gnproc || echo 1)', cwd='~/.hammer-tmp/libyang-cpp/build')
|
|
|
|
execute('sudo make install', cwd='~/.hammer-tmp/libyang-cpp/build')
|
2022-10-07 15:27:08 +03:00
|
|
|
system, revision = get_system_revision()
|
|
|
|
if system != 'alpine':
|
|
|
|
execute('sudo ldconfig')
|
|
|
|
except Exception as e:
|
|
|
|
log.exception(str(e))
|
|
|
|
if not ignore_errors:
|
|
|
|
raise e
|
|
|
|
finally:
|
2022-11-29 20:59:19 +02:00
|
|
|
execute('rm -rf ~/.hammer-tmp')
|
2022-10-07 15:27:08 +03:00
|
|
|
|
|
|
|
|
|
|
|
def _install_sysrepo_cpp_from_sources(ignore_errors = False):
|
|
|
|
"""Install sysrepo-cpp from sources."""
|
|
|
|
for prefix in ['/usr', '/usr/local']:
|
|
|
|
sysrepo_cpp_so = f'{prefix}/lib/libsysrepo-cpp.so'
|
|
|
|
sysrepo_cpp_pc = f'{prefix}/lib/pkgconfig/sysrepo-cpp.pc'
|
|
|
|
if (os.path.exists(sysrepo_cpp_so) and os.path.exists(sysrepo_cpp_pc) and
|
|
|
|
execute(f"grep -F 'Version: 1.1.0' '{sysrepo_cpp_pc}'", raise_error=False) == 0):
|
|
|
|
log.info(f'sysrepo-cpp is already installed at {sysrepo_cpp_so}.')
|
|
|
|
return
|
|
|
|
|
2022-11-09 10:51:43 +02:00
|
|
|
version='02634174ffc60568301c3d9b9b7cf710cff6a586'
|
2022-10-07 15:27:08 +03:00
|
|
|
|
2022-11-29 20:59:19 +02:00
|
|
|
execute('rm -rf ~/.hammer-tmp')
|
|
|
|
execute('mkdir -p ~/.hammer-tmp')
|
2022-10-07 15:27:08 +03:00
|
|
|
try:
|
2022-11-29 20:59:19 +02:00
|
|
|
execute('git clone https://github.com/sysrepo/sysrepo-cpp.git ~/.hammer-tmp/sysrepo-cpp')
|
|
|
|
execute(f'git checkout {version}', cwd='~/.hammer-tmp/sysrepo-cpp')
|
|
|
|
execute('mkdir ~/.hammer-tmp/sysrepo-cpp/build')
|
|
|
|
execute('cmake -DBUILD_TESTING=OFF .. ', cwd='~/.hammer-tmp/sysrepo-cpp/build')
|
|
|
|
execute('make -j $(nproc || gnproc || echo 1)', cwd='~/.hammer-tmp/sysrepo-cpp/build')
|
|
|
|
execute('sudo make install', cwd='~/.hammer-tmp/sysrepo-cpp/build')
|
2022-10-07 15:27:08 +03:00
|
|
|
system, revision = get_system_revision()
|
|
|
|
if system != 'alpine':
|
|
|
|
execute('sudo ldconfig')
|
|
|
|
except Exception as e:
|
|
|
|
log.exception(str(e))
|
|
|
|
if not ignore_errors:
|
|
|
|
raise e
|
|
|
|
finally:
|
2022-11-29 20:59:19 +02:00
|
|
|
execute('rm -rf ~/.hammer-tmp')
|
2022-10-07 15:27:08 +03:00
|
|
|
|
|
|
|
|
|
|
|
def _install_netconf_libraries_from_sources(ignore_errors = False):
|
|
|
|
_install_libyang_from_sources(ignore_errors)
|
|
|
|
_install_sysrepo_from_sources(ignore_errors)
|
|
|
|
_install_libyang_cpp_from_sources(ignore_errors)
|
|
|
|
_install_sysrepo_cpp_from_sources(ignore_errors)
|
|
|
|
|
|
|
|
|
2021-04-19 15:41:40 +03:00
|
|
|
def _get_local_timezone():
|
2021-04-19 12:42:30 +03:00
|
|
|
_, output = execute('''
|
|
|
|
# timedatectl
|
|
|
|
if command -v timedatectl > /dev/null 2>&1; then
|
|
|
|
timedatectl | grep 'Time zone' | cut -d ':' -f 2 | cut -d '(' -f 1 | xargs
|
|
|
|
exit ${?}
|
|
|
|
fi
|
|
|
|
|
2021-04-19 15:41:40 +03:00
|
|
|
# brute force: for Alpine, FreeBSD
|
2021-06-29 13:21:48 +03:00
|
|
|
for i in $(find /usr/share/zoneinfo | cut -d '/' -f 5- | grep -E '^[A-Z][a-z]+/[A-Z][a-z]+.*$' | sort -ruV); do
|
2021-04-19 12:42:30 +03:00
|
|
|
unset TZ
|
|
|
|
if test "$(date)" = "$(TZ="${i}" date)"; then
|
|
|
|
printf '%s\n' "${i}"
|
|
|
|
break
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
''', capture=True, quiet=True)
|
2021-04-19 15:41:40 +03:00
|
|
|
return output.rstrip()
|
2021-04-19 12:42:30 +03:00
|
|
|
|
|
|
|
|
2019-01-24 17:54:20 +01:00
|
|
|
def _configure_mysql(system, revision, features):
|
2019-01-31 11:36:38 +01:00
|
|
|
"""Configure MySQL database."""
|
2022-03-11 16:38:50 +02:00
|
|
|
|
|
|
|
# Find MySQL's configuration directory which differs on various systems.
|
|
|
|
conf_d = None
|
|
|
|
for i in ['/etc/mysql/conf.d', '/etc/my.cnf.d']:
|
|
|
|
if os.path.isdir(i):
|
|
|
|
conf_d = i
|
|
|
|
break
|
|
|
|
if conf_d is None:
|
|
|
|
# No configuration directory found. This happens on some systems like
|
|
|
|
# Alpine. Consider /etc/my.cnf.d as default.
|
|
|
|
conf_d = '/etc/my.cnf.d'
|
|
|
|
execute('sudo mkdir -p {}'.format(conf_d))
|
|
|
|
|
|
|
|
# Some systems like Alpine only listen on the unix socket and have to have
|
|
|
|
# the bind-address configured manually.
|
|
|
|
return_code = execute("sudo grep -Er '^bind-address' {}".format(conf_d), raise_error=False)
|
|
|
|
if return_code != 0:
|
|
|
|
execute("printf '[mysqld]\nbind-address = 127.0.0.1\n' > ./bind-address.cnf")
|
|
|
|
bind_address_cnf = os.path.join(conf_d, 'bind-address.cnf')
|
|
|
|
execute('sudo cp ./bind-address.cnf {}'.format(bind_address_cnf))
|
|
|
|
execute('sudo chown mysql:mysql {}'.format(bind_address_cnf))
|
|
|
|
execute('sudo rm -f ./bind-address.cnf')
|
|
|
|
|
|
|
|
# If requested, configure TLS.
|
|
|
|
cert_dir = '/etc/mysql/ssl'
|
|
|
|
kea_cnf = os.path.join(conf_d, 'kea.cnf')
|
|
|
|
# But start fresh first. Not enabling TLS in hammer leaves TLS support removed.
|
|
|
|
execute('sudo rm -rf {} {}'.format(cert_dir, kea_cnf))
|
|
|
|
if 'tls' in features:
|
|
|
|
if not os.path.isdir(cert_dir):
|
|
|
|
execute('sudo mkdir -p {}'.format(cert_dir))
|
|
|
|
for file in [
|
|
|
|
'./src/lib/asiolink/testutils/ca/kea-ca.crt',
|
|
|
|
'./src/lib/asiolink/testutils/ca/kea-client.crt',
|
|
|
|
'./src/lib/asiolink/testutils/ca/kea-client.key',
|
|
|
|
'./src/lib/asiolink/testutils/ca/kea-server.crt',
|
|
|
|
'./src/lib/asiolink/testutils/ca/kea-server.key',
|
|
|
|
]:
|
|
|
|
if not os.path.exists(file):
|
|
|
|
print('ERROR: File {} is needed to prepare TLS.'.format(file), file=sys.stderr)
|
|
|
|
sys.exit(1)
|
|
|
|
basename = os.path.basename(file)
|
|
|
|
execute('sudo cp {} {}'.format(file, os.path.join(cert_dir, basename)))
|
|
|
|
with open('kea.cnf', 'w', encoding='utf-8') as f:
|
|
|
|
f.write('''\
|
|
|
|
[mysqld]
|
|
|
|
ssl_ca = {cert_dir}/kea-ca.crt
|
|
|
|
ssl_cert = {cert_dir}/kea-server.crt
|
|
|
|
ssl_key = {cert_dir}/kea-server.key
|
|
|
|
|
|
|
|
[client-mariadb]
|
|
|
|
ssl_ca = {cert_dir}/kea-ca.crt
|
|
|
|
ssl_cert = {cert_dir}/kea-client.crt
|
|
|
|
ssl_key = {cert_dir}/kea-client.key
|
|
|
|
'''.format(cert_dir=cert_dir))
|
|
|
|
execute('sudo mv ./kea.cnf {}'.format(kea_cnf))
|
|
|
|
# For all added files and directories, change owner to mysql.
|
|
|
|
execute('sudo chown -R mysql:mysql {} {}'.format(cert_dir, kea_cnf))
|
|
|
|
|
2022-05-12 12:34:45 +02:00
|
|
|
if system in ['debian', 'fedora', 'centos', 'rhel']:
|
2019-01-10 17:36:02 +01:00
|
|
|
execute('sudo systemctl enable mariadb.service')
|
2022-03-11 16:38:50 +02:00
|
|
|
execute('sudo systemctl restart mariadb.service')
|
2019-01-30 18:11:18 +01:00
|
|
|
|
2021-09-06 22:30:10 +03:00
|
|
|
elif system == 'ubuntu':
|
2021-09-03 14:59:12 +03:00
|
|
|
execute('sudo systemctl enable mysql.service')
|
|
|
|
execute('sudo systemctl restart mysql.service')
|
|
|
|
|
2019-09-26 15:20:05 +02:00
|
|
|
elif system == 'freebsd':
|
2019-01-31 11:36:38 +01:00
|
|
|
cmd = "echo 'SET PASSWORD = \"\";' "
|
2020-12-03 00:26:59 +01:00
|
|
|
cmd += "| sudo mysql -u root --password=\"$(sudo cat /root/.mysql_secret | grep -v '^#')\" --connect-expired-password"
|
2019-01-30 18:11:18 +01:00
|
|
|
execute(cmd, raise_error=False)
|
|
|
|
|
2019-09-26 15:20:05 +02:00
|
|
|
elif system == 'alpine':
|
2022-07-22 01:14:23 -07:00
|
|
|
execute('sudo sed -i "/^skip-networking$/d" /etc/my.cnf.d/mariadb-server.cnf')
|
2019-09-26 15:20:05 +02:00
|
|
|
execute('sudo rc-update add mariadb')
|
|
|
|
execute('sudo /etc/init.d/mariadb setup', raise_error=False)
|
2022-03-11 16:38:50 +02:00
|
|
|
execute('sudo /etc/init.d/mariadb restart')
|
2019-09-26 15:20:05 +02:00
|
|
|
|
2019-01-10 17:36:02 +01:00
|
|
|
cmd = "echo 'DROP DATABASE IF EXISTS keatest;' | sudo mysql -u root"
|
|
|
|
execute(cmd)
|
|
|
|
cmd = "echo 'DROP USER 'keatest'@'localhost';' | sudo mysql -u root"
|
|
|
|
execute(cmd, raise_error=False)
|
|
|
|
cmd = "echo 'DROP USER 'keatest_readonly'@'localhost';' | sudo mysql -u root"
|
|
|
|
execute(cmd, raise_error=False)
|
2022-03-11 16:38:50 +02:00
|
|
|
cmd = "echo 'DROP USER 'keatest_secure'@'localhost';' | sudo mysql -u root"
|
|
|
|
execute(cmd, raise_error=False)
|
2019-01-10 17:36:02 +01:00
|
|
|
cmd = "bash -c \"cat <<EOF | sudo mysql -u root\n"
|
|
|
|
cmd += "CREATE DATABASE keatest;\n"
|
|
|
|
cmd += "CREATE USER 'keatest'@'localhost' IDENTIFIED BY 'keatest';\n"
|
|
|
|
cmd += "CREATE USER 'keatest_readonly'@'localhost' IDENTIFIED BY 'keatest';\n"
|
2022-03-11 16:38:50 +02:00
|
|
|
if 'tls' in features:
|
|
|
|
cmd += "CREATE USER 'keatest_secure'@'localhost' IDENTIFIED BY 'keatest';\n"
|
2019-01-10 17:36:02 +01:00
|
|
|
cmd += "GRANT ALL ON keatest.* TO 'keatest'@'localhost';\n"
|
|
|
|
cmd += "GRANT SELECT ON keatest.* TO 'keatest_readonly'@'localhost';\n"
|
|
|
|
cmd += "EOF\n\""
|
|
|
|
execute(cmd)
|
2022-04-07 11:14:12 +03:00
|
|
|
if 'tls' in features:
|
|
|
|
# ALTER USER is the best place to put the REQUIRE but, if it is not
|
|
|
|
# supported, then downgrade to GRANT.
|
|
|
|
exit_code = execute('''sudo mysql -u root -e "ALTER USER 'keatest_secure'@'localhost' REQUIRE X509;"''', raise_error=False)
|
|
|
|
if exit_code == 0:
|
|
|
|
# If ALTER succeeds, then we still have to GRANT without REQUIRE.
|
|
|
|
execute('''sudo mysql -u root -e "GRANT ALL ON keatest.* TO 'keatest_secure'@'localhost';"''')
|
|
|
|
else:
|
|
|
|
execute('''sudo mysql -u root -e "GRANT ALL ON keatest.* TO 'keatest_secure'@'localhost' REQUIRE X509;"''')
|
|
|
|
execute('sudo mysql -u root -e "SET @@global.log_bin_trust_function_creators = 1;"')
|
2019-01-10 17:36:02 +01:00
|
|
|
|
2019-01-24 17:54:20 +01:00
|
|
|
if 'forge' in features:
|
|
|
|
cmd = "echo 'DROP DATABASE IF EXISTS keadb;' | sudo mysql -u root"
|
|
|
|
execute(cmd)
|
|
|
|
cmd = "echo 'DROP USER 'keauser'@'localhost';' | sudo mysql -u root"
|
|
|
|
execute(cmd, raise_error=False)
|
|
|
|
cmd = "bash -c \"cat <<EOF | sudo mysql -u root\n"
|
|
|
|
cmd += "CREATE DATABASE keadb;\n"
|
|
|
|
cmd += "CREATE USER 'keauser'@'localhost' IDENTIFIED BY 'keapass';\n"
|
|
|
|
cmd += "GRANT ALL ON keadb.* TO 'keauser'@'localhost';\n"
|
|
|
|
cmd += "EOF\n\""
|
|
|
|
execute(cmd)
|
|
|
|
|
2019-01-23 11:26:33 +01:00
|
|
|
if system == 'debian' and revision == '9':
|
2022-03-11 16:38:50 +02:00
|
|
|
log.info('FIX FOR ISSUE kea#389: {} {}'.format(system, revision))
|
2019-01-23 11:26:33 +01:00
|
|
|
cmd = "bash -c \"cat <<EOF | sudo mysql -u root\n"
|
|
|
|
cmd += "use keatest;\n"
|
|
|
|
cmd += "set global innodb_large_prefix=on;\n"
|
|
|
|
cmd += "set global innodb_file_format=Barracuda;\n"
|
|
|
|
cmd += "set global innodb_file_per_table=true;\n"
|
|
|
|
cmd += "set global innodb_default_row_format=dynamic;\n"
|
|
|
|
cmd += "EOF\n\""
|
|
|
|
execute(cmd)
|
|
|
|
|
2019-01-10 17:36:02 +01:00
|
|
|
|
2022-06-13 18:03:32 +02:00
|
|
|
def _enable_postgresql(system, revision):
|
2021-04-20 13:06:24 +03:00
|
|
|
if system == 'alpine':
|
|
|
|
execute('sudo rc-update add postgresql')
|
2021-05-04 22:05:27 +02:00
|
|
|
elif system == 'freebsd':
|
|
|
|
execute('sudo sysrc postgresql_enable="yes"')
|
2021-04-20 13:06:24 +03:00
|
|
|
else:
|
2022-09-05 21:59:12 +03:00
|
|
|
# Disable all PostgreSQL services first to avoid conflicts.
|
|
|
|
# raise_error=False for when there are no matches
|
|
|
|
_, output = execute("systemctl list-unit-files | grep postgres | grep -Fv '@.service' | cut -d ' ' -f 1",
|
|
|
|
capture=True, raise_error=False)
|
|
|
|
for service in output.split():
|
|
|
|
execute(f'sudo systemctl disable {service}')
|
|
|
|
|
2021-04-20 13:06:24 +03:00
|
|
|
execute('sudo systemctl enable postgresql.service')
|
|
|
|
|
|
|
|
|
2022-06-13 18:03:32 +02:00
|
|
|
def _restart_postgresql(system, revision):
|
2021-04-20 09:04:42 +03:00
|
|
|
if system == 'freebsd':
|
|
|
|
# redirecting output from start script to /dev/null otherwise the postgresql rc.d script will hang
|
|
|
|
# calling restart instead of start allow hammer.py to pass even if postgresql is already installed
|
|
|
|
execute('sudo service postgresql restart > /dev/null')
|
|
|
|
elif system == 'alpine':
|
|
|
|
execute('sudo /etc/init.d/postgresql restart')
|
|
|
|
else:
|
2022-09-05 21:59:12 +03:00
|
|
|
# Stop all PostgreSQL services first to avoid conflicts.
|
|
|
|
# raise_error=False for when there are no matches
|
|
|
|
_, output = execute("systemctl list-unit-files | grep postgres | grep -Fv '@.service' | cut -d ' ' -f 1",
|
|
|
|
capture=True, raise_error=False)
|
|
|
|
for service in output.split():
|
|
|
|
execute(f'sudo systemctl stop {service}')
|
|
|
|
|
|
|
|
exit_code = execute('sudo systemctl restart postgresql.service', raise_error=False)
|
|
|
|
if exit_code != 0:
|
|
|
|
log.error('Command "sudo systemctl restart postgresql.service" failed. Here is the journal:')
|
|
|
|
_, output = execute('sudo journalctl -xu postgresql.service', capture=True)
|
|
|
|
log.error(output)
|
|
|
|
log.error('And here are logs:')
|
|
|
|
_, output = execute("sudo -u postgres psql -A -t -c 'SELECT pg_current_logfile()'", capture=True)
|
|
|
|
logfile = os.path.basename(output.strip())
|
|
|
|
_, output = execute(f'sudo find /var -type f -name "{logfile}" -exec cat {{}} \;', capture=True, raise_error=False)
|
|
|
|
log.error(output)
|
|
|
|
sys.exit(exit_code)
|
2021-04-20 09:04:42 +03:00
|
|
|
|
|
|
|
|
2021-09-03 15:00:03 +03:00
|
|
|
# Change authentication type for given connection type. Usual inputs for
|
|
|
|
# connection type are 'host' or 'local'. Only affects entries with database
|
|
|
|
# and user both set to 'all'. This is to not affect authentication of
|
|
|
|
# `postgres` user which should have a separate entry.
|
2021-09-01 13:39:57 +03:00
|
|
|
def _change_postgresql_auth_method(connection_type, auth_method, hba_file):
|
2021-09-03 15:00:03 +03:00
|
|
|
execute("sudo sed -i.bak 's/^{}\(.*\)all\(.*\)all\(.*\) [a-z0-9]*$/{}\\1all\\2all\\3 {}/g' '{}'".format(
|
2021-09-01 13:39:57 +03:00
|
|
|
connection_type, connection_type, auth_method, hba_file), cwd='/tmp')
|
|
|
|
|
|
|
|
|
2022-06-13 18:03:32 +02:00
|
|
|
def _configure_pgsql(system, features, revision):
|
2019-08-10 21:47:38 +02:00
|
|
|
""" Configure PostgreSQL DB """
|
2021-09-01 13:39:57 +03:00
|
|
|
|
|
|
|
# execute() calls will set cwd='/tmp' when switching user to postgres to
|
|
|
|
# avoid the error:
|
|
|
|
# could not change as postgres user directory to "/home/jenkins": Permission denied
|
|
|
|
|
2022-05-12 12:34:45 +02:00
|
|
|
if system in ['fedora', 'centos', 'rhel']:
|
2019-01-10 17:36:02 +01:00
|
|
|
# https://fedoraproject.org/wiki/PostgreSQL
|
2019-01-11 16:32:55 +01:00
|
|
|
exitcode = execute('sudo ls /var/lib/pgsql/data/postgresql.conf', raise_error=False)
|
2019-01-10 17:36:02 +01:00
|
|
|
if exitcode != 0:
|
2019-03-25 09:02:18 +01:00
|
|
|
if system == 'centos':
|
|
|
|
execute('sudo postgresql-setup initdb')
|
|
|
|
else:
|
|
|
|
execute('sudo postgresql-setup --initdb --unit postgresql')
|
2019-08-10 21:47:38 +02:00
|
|
|
elif system == 'freebsd':
|
2021-11-10 21:04:19 +02:00
|
|
|
# Stop any hypothetical existing postgres service.
|
|
|
|
execute('sudo service postgresql stop || true')
|
|
|
|
|
2021-11-15 18:34:27 +02:00
|
|
|
# Get the path to the data directory e.g. /var/db/postgres/data11 for
|
|
|
|
# FreeBSD 12 and /var/db/postgres/data13 for FreeBSD 13.
|
|
|
|
_, output = execute('ls -1d /var/db/postgres/data*', capture=True)
|
2021-11-10 21:04:19 +02:00
|
|
|
var_db_postgres_data = output.rstrip()
|
|
|
|
|
|
|
|
# Create postgres internals.
|
|
|
|
execute('sudo test ! -d {} && sudo /usr/local/etc/rc.d/postgresql oneinitdb || true'.format(var_db_postgres_data))
|
|
|
|
|
|
|
|
# if the file '/var/db/postgres/data*/postmaster.opts' does not exist the 'restart' of postgresql will fail with error:
|
|
|
|
# pg_ctl: could not read file "/var/db/postgres/data*/postmaster.opts"
|
2021-05-04 22:05:27 +02:00
|
|
|
# the initial start of the postgresql will create the 'postmaster.opts' file
|
2021-11-10 21:04:19 +02:00
|
|
|
execute('sudo test ! -f {}/postmaster.opts && sudo service postgresql onestart || true'.format(var_db_postgres_data))
|
2019-08-10 21:47:38 +02:00
|
|
|
|
2022-06-13 18:03:32 +02:00
|
|
|
_enable_postgresql(system, revision)
|
|
|
|
_restart_postgresql(system, revision)
|
2021-04-20 09:04:42 +03:00
|
|
|
|
2021-09-03 15:00:03 +03:00
|
|
|
# Change auth-method to 'md5' on all connections.
|
|
|
|
cmd = "sudo -u postgres psql -t -c 'SHOW hba_file' | xargs"
|
|
|
|
_, output = execute(cmd, capture=True, cwd='/tmp')
|
|
|
|
hba_file = output.rstrip()
|
|
|
|
_change_postgresql_auth_method('host', 'md5', hba_file)
|
|
|
|
_change_postgresql_auth_method('local', 'md5', hba_file)
|
|
|
|
|
2021-09-06 20:28:26 +03:00
|
|
|
# Make sure hba file has a postgres superuser entry. It needs to be placed
|
|
|
|
# before any other local auth method for higher priority. Let's simulate
|
|
|
|
# that by putting it just after the auth header.
|
|
|
|
if 0 != execute("sudo cat {} | grep -E '^local.*all.*postgres'".format(hba_file), raise_error=False):
|
|
|
|
auth_header='# TYPE DATABASE USER ADDRESS METHOD'
|
|
|
|
postgres_auth_line='local all postgres ident'
|
2021-11-10 21:04:19 +02:00
|
|
|
# The "\\" followed by newline is for BSD support.
|
|
|
|
execute("""sudo sed -i.bak '/{}/a\\
|
|
|
|
{}
|
|
|
|
' '{}'""".format(auth_header, postgres_auth_line, hba_file))
|
2021-09-06 20:28:26 +03:00
|
|
|
|
2022-06-13 18:03:32 +02:00
|
|
|
_restart_postgresql(system, revision)
|
2021-09-03 15:00:03 +03:00
|
|
|
|
2021-04-16 14:03:52 +03:00
|
|
|
cmd = """bash -c \"cat <<EOF | sudo -u postgres psql postgres
|
|
|
|
DROP DATABASE IF EXISTS keatest;
|
|
|
|
DROP USER IF EXISTS keatest;
|
|
|
|
DROP USER IF EXISTS keatest_readonly;
|
|
|
|
CREATE USER keatest WITH PASSWORD 'keatest';
|
|
|
|
CREATE USER keatest_readonly WITH PASSWORD 'keatest';
|
|
|
|
CREATE DATABASE keatest;
|
|
|
|
GRANT ALL PRIVILEGES ON DATABASE keatest TO keatest;
|
2021-04-19 15:41:40 +03:00
|
|
|
ALTER DATABASE keatest SET TIMEZONE='{}';\n""".format(_get_local_timezone())
|
2021-04-16 14:03:52 +03:00
|
|
|
cmd += 'EOF\n"'
|
2021-09-01 13:39:57 +03:00
|
|
|
execute(cmd, cwd='/tmp')
|
2019-01-10 17:36:02 +01:00
|
|
|
|
2023-06-28 11:19:15 +02:00
|
|
|
if system == 'fedora' and int(revision) >= 38 or \
|
|
|
|
system == 'debian' and int(revision) >= 12 or \
|
|
|
|
system == 'alpine' and float(revision) >= 3.17:
|
|
|
|
#TODO it needs detection of pgsql version, and apply this only for postgres >= 15
|
|
|
|
cmd = """bash -c \"cat <<EOF | sudo -u postgres psql postgres
|
|
|
|
GRANT ALL ON DATABASE keatest TO keatest;
|
|
|
|
ALTER DATABASE keatest OWNER TO keatest;\n"""
|
|
|
|
cmd += 'EOF\n"'
|
|
|
|
execute(cmd, cwd='/tmp')
|
|
|
|
|
2021-04-20 13:06:24 +03:00
|
|
|
cmd = """bash -c \"cat <<EOF | sudo -u postgres psql -U keatest keatest
|
2021-04-20 12:53:54 +03:00
|
|
|
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO keatest_readonly;\n"""
|
|
|
|
cmd += 'EOF\n"'
|
2021-04-20 13:06:24 +03:00
|
|
|
env = os.environ.copy()
|
|
|
|
env['PGPASSWORD'] = 'keatest'
|
2021-09-01 13:39:57 +03:00
|
|
|
execute(cmd, cwd='/tmp', env=env)
|
2021-04-16 14:03:52 +03:00
|
|
|
|
2019-01-24 17:54:20 +01:00
|
|
|
if 'forge' in features:
|
|
|
|
cmd = "bash -c \"cat <<EOF | sudo -u postgres psql postgres\n"
|
|
|
|
cmd += "DROP DATABASE IF EXISTS keadb;\n"
|
|
|
|
cmd += "DROP USER IF EXISTS keauser;\n"
|
|
|
|
cmd += "CREATE USER keauser WITH PASSWORD 'keapass';\n"
|
|
|
|
cmd += "CREATE DATABASE keadb;\n"
|
|
|
|
cmd += "GRANT ALL PRIVILEGES ON DATABASE keauser TO keadb;\n"
|
|
|
|
cmd += "EOF\n\""
|
2021-09-01 13:39:57 +03:00
|
|
|
execute(cmd, cwd='/tmp')
|
|
|
|
|
2019-03-25 09:02:18 +01:00
|
|
|
log.info('postgresql just configured')
|
2019-01-24 17:54:20 +01:00
|
|
|
|
2019-01-10 17:36:02 +01:00
|
|
|
|
2019-07-22 10:52:40 +02:00
|
|
|
def _apt_update(system, revision, env=None, check_times=False, attempts=1, sleep_time_after_attempt=None,
|
|
|
|
capture=False):
|
|
|
|
cmd = 'sudo apt update'
|
|
|
|
if system == 'debian' and int(revision) >= 10:
|
|
|
|
cmd += ' --allow-releaseinfo-change'
|
|
|
|
return execute(cmd, env=env, check_times=check_times, attempts=attempts,
|
|
|
|
sleep_time_after_attempt=sleep_time_after_attempt, capture=capture)
|
|
|
|
|
|
|
|
|
2019-04-10 10:50:15 +02:00
|
|
|
def _install_freeradius_client(system, revision, features, env, check_times):
|
2019-03-25 09:02:18 +01:00
|
|
|
"""Install FreeRADIUS-client with necessary patches from Francis Dupont."""
|
2019-04-10 10:50:15 +02:00
|
|
|
# check if it is already installed
|
2022-09-05 19:32:22 +03:00
|
|
|
if (os.path.exists('/usr/local/lib/libfreeradius-client.so') and
|
2019-03-25 09:02:18 +01:00
|
|
|
os.path.exists('/usr/local/include/freeradius-client.h')):
|
2022-03-10 09:58:39 +02:00
|
|
|
log.info('freeradius-client is already installed.')
|
2019-03-25 09:02:18 +01:00
|
|
|
return
|
2019-04-10 10:50:15 +02:00
|
|
|
|
2022-03-10 09:58:39 +02:00
|
|
|
# Install freeradius-client dependencies.
|
2019-04-10 10:50:15 +02:00
|
|
|
if system in ['centos', 'rhel', 'fedora']:
|
|
|
|
install_pkgs('nettle-devel', env=env, check_times=check_times)
|
2021-04-23 18:01:16 +03:00
|
|
|
elif system in ['alpine', 'debian', 'ubuntu']:
|
2019-04-10 10:50:15 +02:00
|
|
|
install_pkgs('nettle-dev', env=env, check_times=check_times)
|
2021-11-03 20:08:46 +02:00
|
|
|
elif system in ['arch', 'freebsd']:
|
2021-04-23 18:01:16 +03:00
|
|
|
install_pkgs('nettle', env=env, check_times=check_times)
|
2019-04-10 10:50:15 +02:00
|
|
|
else:
|
2019-09-26 15:20:05 +02:00
|
|
|
raise NotImplementedError('no implementation for %s' % system)
|
2019-04-10 10:50:15 +02:00
|
|
|
|
|
|
|
# checkout sources, build them and install
|
2019-03-25 09:02:18 +01:00
|
|
|
execute('rm -rf freeradius-client')
|
|
|
|
execute('git clone https://github.com/fxdupont/freeradius-client.git', env=env, check_times=check_times)
|
|
|
|
execute('git checkout iscdev', cwd='freeradius-client', env=env, check_times=check_times)
|
2019-04-10 10:50:15 +02:00
|
|
|
execute('./configure --with-nettle', cwd='freeradius-client', env=env, check_times=check_times)
|
2019-03-25 09:02:18 +01:00
|
|
|
execute('make', cwd='freeradius-client', env=env, check_times=check_times)
|
|
|
|
execute('sudo make install', cwd='freeradius-client', env=env, check_times=check_times)
|
|
|
|
execute('rm -rf freeradius-client')
|
2022-10-13 14:04:25 +03:00
|
|
|
if system != 'alpine':
|
|
|
|
execute('sudo ldconfig', env=env)
|
2022-03-10 09:58:39 +02:00
|
|
|
log.info('freeradius-client successfully installed.')
|
2019-03-25 09:02:18 +01:00
|
|
|
|
|
|
|
|
2022-10-07 15:27:08 +03:00
|
|
|
def _get_package_version(package: str):
|
|
|
|
"""
|
|
|
|
Returns the version available in the package manager's repository for the requested package.
|
|
|
|
:param package: the name of the package whose version is retrieved
|
|
|
|
"""
|
|
|
|
system, revision = get_system_revision()
|
|
|
|
if system == 'alpine':
|
|
|
|
cmd = "apk search --exact {0} | sed 's/{0}-//g'"
|
|
|
|
elif system in ['debian', 'ubuntu']:
|
|
|
|
cmd = "apt-cache show {} | grep -F 'Version:' | cut -d ' ' -f 2"
|
|
|
|
elif system in ['centos', 'fedora', 'rhel']:
|
|
|
|
cmd = "dnf list {} | tr -s ' ' | cut -d ' ' -f 2 | tail -n 1"
|
|
|
|
elif system == 'freebsd':
|
|
|
|
cmd = "pkg search {0} | grep -Eo '^{0}-[0-9_,\.]+' | sed 's/{0}-//g'"
|
|
|
|
elif system == 'arch':
|
|
|
|
cmd = "pacman -Qi {} | tr -s ' ' | grep -F 'Version :' | cut -d ' ' -f 3"
|
|
|
|
else:
|
|
|
|
raise NotImplementedError(f'_get_package_version not implemented for {system}')
|
|
|
|
|
|
|
|
cmd = cmd.format(package)
|
|
|
|
_, output = execute(cmd, capture=True)
|
|
|
|
return output.strip()
|
|
|
|
|
|
|
|
|
|
|
|
def require_minimum_package_version(package: str, minimum: str):
|
|
|
|
"""
|
|
|
|
Returns true if a given package is available to be installed with
|
|
|
|
the given minimum version or greater.
|
|
|
|
:param package: the name of the package that is checked
|
|
|
|
:param minimum: the semantic version that the package is checked against
|
|
|
|
"""
|
|
|
|
version = _get_package_version(package)
|
|
|
|
if version < minimum:
|
|
|
|
message = f"ERROR: {package} has version {version}, but must be >= {minimum}"
|
|
|
|
log.error(message)
|
|
|
|
raise Exception(message)
|
|
|
|
|
|
|
|
|
|
|
|
def prepare_system_local(features, check_times, ignore_errors_for):
|
2019-01-29 11:30:05 +01:00
|
|
|
"""Prepare local system for Kea development based on requested features."""
|
2019-01-10 17:36:02 +01:00
|
|
|
env = os.environ.copy()
|
|
|
|
env['LANGUAGE'] = env['LANG'] = env['LC_ALL'] = 'C'
|
|
|
|
|
2021-08-05 18:12:10 +03:00
|
|
|
# Actions decided before installing packages, but run afterwards
|
|
|
|
deferred_functions = []
|
|
|
|
|
2018-12-27 15:15:08 +01:00
|
|
|
system, revision = get_system_revision()
|
|
|
|
log.info('Preparing deps for %s %s', system, revision)
|
|
|
|
|
2022-10-07 15:27:08 +03:00
|
|
|
# Check if package versions cannot be met.
|
|
|
|
if 'netconf' in features and 'netconf' not in ignore_errors_for:
|
|
|
|
require_minimum_package_version('cmake', '3.19')
|
2021-08-05 18:12:10 +03:00
|
|
|
|
2019-01-29 11:30:05 +01:00
|
|
|
# prepare fedora
|
2018-12-27 15:15:08 +01:00
|
|
|
if system == 'fedora':
|
2019-01-31 11:36:38 +01:00
|
|
|
packages = ['make', 'autoconf', 'automake', 'libtool', 'gcc-c++', 'openssl-devel',
|
2022-09-05 22:30:57 +03:00
|
|
|
'log4cplus-devel', 'boost-devel', 'libpcap-devel']
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
if 'native-pkg' in features:
|
2021-05-17 08:57:57 +02:00
|
|
|
packages.extend(['rpm-build', 'python3-devel'])
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-01-10 17:36:02 +01:00
|
|
|
if 'docs' in features:
|
2019-07-24 09:58:40 +02:00
|
|
|
packages.extend(['python3-sphinx', 'texlive', 'texlive-collection-latexextra'])
|
2019-12-20 09:58:04 +01:00
|
|
|
if int(revision) >= 31:
|
|
|
|
packages.extend(['python3-sphinx_rtd_theme'])
|
2019-01-10 17:36:02 +01:00
|
|
|
|
|
|
|
if 'mysql' in features:
|
2019-06-24 21:58:48 +02:00
|
|
|
execute('sudo dnf remove -y community-mysql-devel || true')
|
2019-04-10 10:50:15 +02:00
|
|
|
packages.extend(['mariadb', 'mariadb-server', 'mariadb-connector-c-devel'])
|
2019-01-10 17:36:02 +01:00
|
|
|
|
|
|
|
if 'pgsql' in features:
|
2019-12-20 09:58:04 +01:00
|
|
|
if int(revision) >= 30:
|
2019-05-14 08:11:34 +02:00
|
|
|
packages.extend(['postgresql-server-devel'])
|
2022-05-18 09:22:15 +02:00
|
|
|
if int(revision) <= 34:
|
|
|
|
packages.extend(['postgresql-devel'])
|
|
|
|
packages.extend(['postgresql-server'])
|
2019-01-10 17:36:02 +01:00
|
|
|
|
2019-01-17 16:41:03 +01:00
|
|
|
if 'radius' in features:
|
2022-03-10 09:58:39 +02:00
|
|
|
packages.extend(['freeradius', 'git'])
|
2019-01-17 16:41:03 +01:00
|
|
|
|
2021-06-28 12:19:36 +02:00
|
|
|
if 'gssapi' in features:
|
|
|
|
packages.extend(['krb5-devel'])
|
|
|
|
|
2019-03-14 16:37:12 +01:00
|
|
|
if 'ccache' in features:
|
|
|
|
packages.extend(['ccache'])
|
|
|
|
|
2021-08-05 18:12:10 +03:00
|
|
|
if 'netconf' in features:
|
2022-10-07 15:27:08 +03:00
|
|
|
packages.extend(['cmake', 'pcre2-devel'])
|
2022-05-18 09:22:15 +02:00
|
|
|
|
2019-01-29 14:46:07 +01:00
|
|
|
install_pkgs(packages, timeout=300, env=env, check_times=check_times)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
if 'unittest' in features:
|
2023-06-20 16:07:57 +00:00
|
|
|
if int(revision) >= 37:
|
2023-06-20 21:09:58 +00:00
|
|
|
install_pkgs(['flex', 'bison'], timeout=300, env=env, check_times=check_times)
|
2018-12-27 15:15:08 +01:00
|
|
|
_install_gtest_sources()
|
|
|
|
|
2019-01-10 17:36:02 +01:00
|
|
|
execute('sudo dnf clean packages', env=env, check_times=check_times)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-01-29 11:30:05 +01:00
|
|
|
# prepare centos
|
2019-01-10 17:36:02 +01:00
|
|
|
elif system == 'centos':
|
2019-01-29 14:46:07 +01:00
|
|
|
install_pkgs('epel-release', env=env, check_times=check_times)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2021-09-11 19:27:06 +03:00
|
|
|
packages = ['autoconf', 'automake', 'boost-devel', 'gcc-c++',
|
2022-07-29 09:51:10 +03:00
|
|
|
'libtool', 'log4cplus-devel', 'make',
|
2022-09-05 21:59:12 +03:00
|
|
|
'openssl-devel']
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2022-09-05 22:30:57 +03:00
|
|
|
if revision in ['7', '8']:
|
2021-09-11 19:27:06 +03:00
|
|
|
# Install newer version of Boost in case users want to opt-in with:
|
|
|
|
# --with-boost-include=/usr/include/boost169 --with-boost-lib-dir=/usr/lib64/boost169
|
2021-08-23 09:59:02 +03:00
|
|
|
packages.append('boost169-devel')
|
2021-08-13 14:03:27 +03:00
|
|
|
|
2019-04-10 10:50:15 +02:00
|
|
|
if 'native-pkg' in features:
|
2022-09-05 22:30:57 +03:00
|
|
|
packages.extend(['bison', 'flex', 'python3-devel', 'rpm-build'])
|
2019-01-10 17:36:02 +01:00
|
|
|
|
|
|
|
if 'mysql' in features:
|
2022-07-29 09:51:10 +03:00
|
|
|
packages.extend(['mariadb', 'mariadb-server'])
|
|
|
|
if int(revision) < 9:
|
|
|
|
packages.extend(['mariadb-devel'])
|
|
|
|
else:
|
|
|
|
packages.extend(['mariadb-connector-c-devel'])
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-01-10 17:36:02 +01:00
|
|
|
if 'pgsql' in features:
|
2022-09-05 21:59:12 +03:00
|
|
|
packages.extend(['postgresql', 'postgresql-server'])
|
|
|
|
if revision == '9':
|
|
|
|
packages.append('postgresql13-devel')
|
2022-10-03 10:56:21 +03:00
|
|
|
def link_pg_config():
|
|
|
|
if not os.path.exists('/usr/bin/pg_config'):
|
|
|
|
execute('sudo ln -s /usr/pgsql-13/bin/pg_config /usr/bin/pg_config')
|
|
|
|
deferred_functions.append(link_pg_config)
|
2022-07-29 09:51:10 +03:00
|
|
|
else:
|
2022-09-05 21:59:12 +03:00
|
|
|
packages.append('postgresql-devel')
|
2019-01-10 17:36:02 +01:00
|
|
|
|
2019-01-17 16:41:03 +01:00
|
|
|
if 'radius' in features:
|
2022-03-10 09:58:39 +02:00
|
|
|
packages.extend(['freeradius', 'git'])
|
2019-01-17 16:41:03 +01:00
|
|
|
|
2021-06-28 12:19:36 +02:00
|
|
|
if 'gssapi' in features:
|
|
|
|
packages.extend(['krb5-devel'])
|
|
|
|
|
2019-03-14 16:37:12 +01:00
|
|
|
if 'ccache' in features:
|
|
|
|
packages.extend(['ccache'])
|
|
|
|
|
2021-08-05 18:12:10 +03:00
|
|
|
if 'netconf' in features:
|
2022-10-07 15:27:08 +03:00
|
|
|
packages.extend(['cmake', 'pcre2-devel'])
|
2021-08-05 18:12:10 +03:00
|
|
|
|
|
|
|
if 'unittest' in features:
|
|
|
|
packages.append('wget')
|
|
|
|
deferred_functions.append(_install_gtest_sources)
|
|
|
|
|
2019-01-29 14:46:07 +01:00
|
|
|
install_pkgs(packages, env=env, check_times=check_times)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-07-24 09:58:40 +02:00
|
|
|
if 'docs' in features:
|
2022-07-29 09:51:10 +03:00
|
|
|
execute('python3 -m venv ~/venv',
|
2019-07-24 09:58:40 +02:00
|
|
|
env=env, timeout=60, check_times=check_times)
|
2023-10-10 18:23:10 +03:00
|
|
|
execute('~/venv/bin/pip install sphinx sphinx-rtd-theme sphinx-tabs',
|
2019-07-24 09:58:40 +02:00
|
|
|
env=env, timeout=120, check_times=check_times)
|
|
|
|
|
2019-01-29 11:30:05 +01:00
|
|
|
# prepare rhel
|
2019-01-10 17:36:02 +01:00
|
|
|
elif system == 'rhel':
|
2021-09-11 19:27:06 +03:00
|
|
|
packages = ['autoconf', 'automake', 'boost-devel', 'gcc-c++',
|
2022-06-13 18:03:32 +02:00
|
|
|
'libtool', 'log4cplus-devel', 'make',
|
2022-09-05 21:59:12 +03:00
|
|
|
'openssl-devel']
|
2021-08-13 14:03:27 +03:00
|
|
|
|
2022-05-13 09:24:28 +02:00
|
|
|
if revision in ['7', '8']:
|
2021-09-11 19:27:06 +03:00
|
|
|
# Install newer version of Boost in case users want to opt-in with:
|
|
|
|
# --with-boost-include=/usr/include/boost169 --with-boost-lib-dir=/usr/lib64/boost169
|
|
|
|
packages.append('boost169-devel')
|
|
|
|
|
|
|
|
if 'native-pkg' in features:
|
2022-09-05 22:30:57 +03:00
|
|
|
packages.extend(['bison', 'flex', 'python3-devel', 'rpm-build'])
|
2022-05-13 09:24:28 +02:00
|
|
|
|
2022-05-12 12:34:45 +02:00
|
|
|
if 'mysql' in features:
|
2022-06-13 18:03:32 +02:00
|
|
|
packages.extend(['mariadb', 'mariadb-server'])
|
|
|
|
if int(revision) < 9:
|
|
|
|
packages.extend(['mariadb-devel'])
|
|
|
|
else:
|
|
|
|
packages.extend(['mariadb-connector-c-devel'])
|
2019-01-10 17:36:02 +01:00
|
|
|
|
2022-05-12 12:34:45 +02:00
|
|
|
if 'pgsql' in features:
|
2022-09-05 21:59:12 +03:00
|
|
|
packages.extend(['postgresql', 'postgresql-server'])
|
|
|
|
if revision == '9':
|
2023-04-18 08:39:15 +02:00
|
|
|
packages.append('postgresql-server-devel ')
|
2022-07-29 09:51:10 +03:00
|
|
|
else:
|
2022-09-05 21:59:12 +03:00
|
|
|
packages.append('postgresql-devel')
|
2019-01-10 17:36:02 +01:00
|
|
|
|
2019-01-17 16:41:03 +01:00
|
|
|
if 'radius' in features:
|
2022-03-10 09:58:39 +02:00
|
|
|
packages.extend(['freeradius', 'git'])
|
2019-01-17 16:41:03 +01:00
|
|
|
|
2022-05-13 09:24:28 +02:00
|
|
|
if 'gssapi' in features:
|
|
|
|
packages.extend(['krb5-devel'])
|
|
|
|
|
2019-03-14 16:37:12 +01:00
|
|
|
if 'ccache' in features:
|
|
|
|
packages.extend(['ccache'])
|
|
|
|
|
2021-08-05 18:12:10 +03:00
|
|
|
if 'netconf' in features:
|
2022-10-07 15:27:08 +03:00
|
|
|
packages.extend(['cmake', 'pcre2-devel'])
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
if 'unittest' in features:
|
2021-08-05 18:12:10 +03:00
|
|
|
packages.append('wget')
|
|
|
|
deferred_functions.append(_install_gtest_sources)
|
|
|
|
|
|
|
|
install_pkgs(packages, env=env, timeout=120, check_times=check_times)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2022-05-13 09:24:28 +02:00
|
|
|
if 'docs' in features:
|
2022-06-13 18:03:32 +02:00
|
|
|
execute('python3 -m venv ~/venv',
|
2022-05-13 09:24:28 +02:00
|
|
|
env=env, timeout=60, check_times=check_times)
|
2023-10-10 18:23:10 +03:00
|
|
|
execute('~/venv/bin/pip install sphinx sphinx-rtd-theme sphinx-tabs',
|
2022-05-13 09:24:28 +02:00
|
|
|
env=env, timeout=120, check_times=check_times)
|
|
|
|
|
2019-01-29 11:30:05 +01:00
|
|
|
# prepare ubuntu
|
2018-12-27 15:15:08 +01:00
|
|
|
elif system == 'ubuntu':
|
2019-07-22 10:52:40 +02:00
|
|
|
_apt_update(system, revision, env=env, check_times=check_times, attempts=3, sleep_time_after_attempt=10)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-01-31 11:36:38 +01:00
|
|
|
packages = ['gcc', 'g++', 'make', 'autoconf', 'automake', 'libtool', 'libssl-dev', 'liblog4cplus-dev',
|
2021-02-16 11:50:25 +01:00
|
|
|
'libboost-system-dev', 'gnupg', 'libpcap-dev', 'python3-venv']
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
if 'unittest' in features:
|
2019-01-10 17:36:02 +01:00
|
|
|
if revision.startswith('16.'):
|
|
|
|
_install_gtest_sources()
|
|
|
|
else:
|
|
|
|
packages.append('googletest')
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
if 'docs' in features:
|
2023-10-10 18:23:10 +03:00
|
|
|
packages.extend(['python3-sphinx', 'python3-sphinx-rtd-theme', 'python3-sphinx-tabs',
|
|
|
|
'texlive', 'texlive-latex-extra'])
|
2022-06-27 13:34:41 +02:00
|
|
|
if revision == '22.04':
|
|
|
|
packages.extend(['tex-gyre'])
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
if 'native-pkg' in features:
|
|
|
|
packages.extend(['build-essential', 'fakeroot', 'devscripts'])
|
2021-09-11 19:51:55 +03:00
|
|
|
packages.extend(['bison', 'debhelper', 'flex', 'libboost-dev', 'python3-dev'])
|
2021-08-05 18:12:10 +03:00
|
|
|
if 20.04 <= float(revision):
|
2020-05-12 11:39:17 +02:00
|
|
|
packages.extend(['dh-python'])
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-01-10 17:36:02 +01:00
|
|
|
if 'mysql' in features:
|
2019-01-29 14:46:07 +01:00
|
|
|
if revision == '16.04':
|
|
|
|
packages.extend(['mysql-client', 'libmysqlclient-dev', 'mysql-server'])
|
|
|
|
else:
|
|
|
|
packages.extend(['default-mysql-client-core', 'default-libmysqlclient-dev', 'mysql-server'])
|
2019-01-10 17:36:02 +01:00
|
|
|
|
|
|
|
if 'pgsql' in features:
|
2019-03-25 09:02:18 +01:00
|
|
|
if revision == '16.04':
|
|
|
|
packages.extend(['postgresql-client', 'libpq-dev', 'postgresql', 'postgresql-server-dev-all'])
|
|
|
|
else:
|
|
|
|
packages.extend(['postgresql-client', 'libpq-dev', 'postgresql-all'])
|
2019-01-10 17:36:02 +01:00
|
|
|
|
2019-01-17 16:41:03 +01:00
|
|
|
if 'radius' in features:
|
2022-03-10 09:58:39 +02:00
|
|
|
packages.extend(['freeradius', 'git'])
|
2019-01-17 16:41:03 +01:00
|
|
|
|
2021-06-28 12:19:36 +02:00
|
|
|
if 'gssapi' in features:
|
|
|
|
packages.extend(['libkrb5-dev'])
|
|
|
|
|
2019-03-14 16:37:12 +01:00
|
|
|
if 'ccache' in features:
|
|
|
|
packages.extend(['ccache'])
|
|
|
|
|
2021-08-05 18:12:10 +03:00
|
|
|
if 'netconf' in features:
|
2022-10-07 15:27:08 +03:00
|
|
|
packages.extend(['cmake', 'libpcre2-dev'])
|
2021-08-05 18:12:10 +03:00
|
|
|
|
2019-01-29 14:46:07 +01:00
|
|
|
install_pkgs(packages, env=env, timeout=240, check_times=check_times)
|
2019-01-10 17:36:02 +01:00
|
|
|
|
2019-01-29 11:30:05 +01:00
|
|
|
# prepare debian
|
2018-12-27 15:15:08 +01:00
|
|
|
elif system == 'debian':
|
2019-07-22 10:52:40 +02:00
|
|
|
_apt_update(system, revision, env=env, check_times=check_times, attempts=3, sleep_time_after_attempt=10)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-01-31 11:36:38 +01:00
|
|
|
packages = ['gcc', 'g++', 'make', 'autoconf', 'automake', 'libtool', 'libssl-dev',
|
2019-08-06 12:46:53 +02:00
|
|
|
'liblog4cplus-dev', 'libboost-system-dev', 'gnupg']
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
if 'unittest' in features:
|
|
|
|
if revision == '8':
|
2019-01-29 11:30:05 +01:00
|
|
|
# libgtest-dev does not work and googletest is not available
|
2019-01-10 17:36:02 +01:00
|
|
|
_install_gtest_sources()
|
2018-12-27 15:15:08 +01:00
|
|
|
else:
|
|
|
|
packages.append('googletest')
|
|
|
|
|
2021-08-05 18:12:10 +03:00
|
|
|
if 'netconf' in features:
|
2023-06-19 13:53:23 +00:00
|
|
|
packages.extend(['cmake', 'libpcre2-dev'])
|
|
|
|
if revision == '12':
|
|
|
|
packages.extend(['doxygen', 'graphviz', 'pkg-config'])
|
2021-08-05 18:12:10 +03:00
|
|
|
|
2019-04-10 10:50:15 +02:00
|
|
|
if 'docs' in features:
|
2019-07-24 09:58:40 +02:00
|
|
|
if revision == '8':
|
|
|
|
packages.extend(['virtualenv'])
|
|
|
|
else:
|
2023-10-10 18:23:10 +03:00
|
|
|
packages.extend(['python3-sphinx', 'python3-sphinx-rtd-theme', 'python3-sphinx-tabs',
|
|
|
|
'texlive', 'texlive-latex-extra'])
|
2019-07-24 09:58:40 +02:00
|
|
|
if revision == '9':
|
|
|
|
packages.extend(['texlive-generic-extra'])
|
2023-06-19 13:53:23 +00:00
|
|
|
if revision == '12':
|
|
|
|
packages.extend(['tex-gyre'])
|
2019-04-10 10:50:15 +02:00
|
|
|
|
|
|
|
if 'native-pkg' in features:
|
|
|
|
packages.extend(['build-essential', 'fakeroot', 'devscripts'])
|
2021-09-11 19:51:55 +03:00
|
|
|
packages.extend(['bison', 'debhelper', 'flex', 'libboost-dev', 'python3-dev'])
|
2021-11-18 13:17:07 +01:00
|
|
|
if int(revision) >= 11:
|
|
|
|
packages.extend(['dh-python'])
|
2019-04-10 10:50:15 +02:00
|
|
|
|
2019-01-10 17:36:02 +01:00
|
|
|
if 'mysql' in features:
|
2019-01-29 14:46:07 +01:00
|
|
|
if revision == '8':
|
2019-06-24 21:58:48 +02:00
|
|
|
packages.extend(['mysql-client', 'libmysqlclient-dev'])
|
2019-01-29 14:46:07 +01:00
|
|
|
else:
|
2019-06-24 21:58:48 +02:00
|
|
|
packages.extend(['default-mysql-client-core', 'default-libmysqlclient-dev'])
|
|
|
|
if revision in ['8', '9']:
|
|
|
|
packages.append('mysql-server')
|
|
|
|
else:
|
|
|
|
packages.append('mariadb-server')
|
2019-01-10 17:36:02 +01:00
|
|
|
|
2019-03-25 09:02:18 +01:00
|
|
|
if 'pgsql' in features:
|
2019-07-26 09:51:32 +02:00
|
|
|
packages.extend(['postgresql-client', 'libpq-dev'])
|
|
|
|
if revision == '8':
|
|
|
|
packages.extend(['postgresql', 'postgresql-client'])
|
|
|
|
else:
|
|
|
|
packages.append('postgresql-all')
|
2019-03-25 09:02:18 +01:00
|
|
|
|
2019-01-17 16:41:03 +01:00
|
|
|
if 'radius' in features:
|
2022-03-10 09:58:39 +02:00
|
|
|
packages.extend(['freeradius', 'git'])
|
2019-01-17 16:41:03 +01:00
|
|
|
|
2021-06-28 12:19:36 +02:00
|
|
|
if 'gssapi' in features:
|
|
|
|
packages.extend(['libkrb5-dev'])
|
|
|
|
|
2019-03-14 16:37:12 +01:00
|
|
|
if 'ccache' in features:
|
|
|
|
packages.extend(['ccache'])
|
|
|
|
|
2019-01-29 14:46:07 +01:00
|
|
|
install_pkgs(packages, env=env, timeout=240, check_times=check_times)
|
2019-01-10 17:36:02 +01:00
|
|
|
|
2022-09-05 22:30:57 +03:00
|
|
|
if 'docs' in features:
|
|
|
|
if revision == '8':
|
|
|
|
execute('python3 -m venv ~/venv',
|
|
|
|
env=env, timeout=60, check_times=check_times)
|
2023-10-10 18:23:10 +03:00
|
|
|
execute('~/venv/bin/pip install sphinx sphinx-rtd-theme sphinx-tabs',
|
2022-09-05 22:30:57 +03:00
|
|
|
env=env, timeout=120, check_times=check_times)
|
2019-07-24 09:58:40 +02:00
|
|
|
|
2019-01-29 11:30:05 +01:00
|
|
|
# prepare freebsd
|
2018-12-27 15:15:08 +01:00
|
|
|
elif system == 'freebsd':
|
2022-09-05 22:32:58 +03:00
|
|
|
# Packages are already upgraded by default when installing a package,
|
|
|
|
# so to avoid mismatching dependency versions, inaccurate dynamic
|
|
|
|
# version fetching and other troubles, clean up local cache and
|
|
|
|
# install an arbitrary package to fetch remote first.
|
|
|
|
execute('sudo pkg clean -a -y')
|
|
|
|
execute('sudo pkg install -y pkg')
|
|
|
|
|
2021-06-07 14:52:51 +02:00
|
|
|
packages = ['autoconf', 'automake', 'libtool', 'openssl', 'log4cplus', 'boost-libs', 'wget']
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-01-10 17:36:02 +01:00
|
|
|
if 'docs' in features:
|
2022-08-26 09:48:13 +02:00
|
|
|
# Get the python version from the remote repositories.
|
2022-10-07 15:27:08 +03:00
|
|
|
pyv = _get_package_version('python')
|
|
|
|
pyv = pyv.split('_')[0].replace('.', '')
|
2022-08-26 09:59:08 +02:00
|
|
|
log.info(">>>>> Detected Sphinx packages version: py%s-sphinx", pyv)
|
2022-08-26 09:48:13 +02:00
|
|
|
packages.extend([f'py{pyv}-sphinx', f'py{pyv}-sphinx_rtd_theme'])
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-01-30 18:11:18 +01:00
|
|
|
if 'mysql' in features:
|
2021-06-08 16:03:51 +02:00
|
|
|
if revision.startswith(('11', '12')):
|
2021-06-07 14:52:51 +02:00
|
|
|
packages.extend(['mysql57-server', 'mysql57-client'])
|
2021-06-08 16:03:51 +02:00
|
|
|
else:
|
|
|
|
packages.extend(['mysql80-server', 'mysql80-client'])
|
2019-01-30 18:11:18 +01:00
|
|
|
|
2019-08-10 21:47:38 +02:00
|
|
|
if 'pgsql' in features:
|
2021-06-08 16:03:51 +02:00
|
|
|
if revision.startswith(('11', '12')):
|
2021-06-07 14:52:51 +02:00
|
|
|
packages.extend(['postgresql11-server', 'postgresql11-client'])
|
2021-06-08 16:03:51 +02:00
|
|
|
else:
|
2021-06-09 13:03:07 +02:00
|
|
|
packages.extend(['postgresql13-server', 'postgresql13-client'])
|
2019-08-10 21:47:38 +02:00
|
|
|
|
2019-01-30 18:11:18 +01:00
|
|
|
if 'radius' in features:
|
2022-03-18 20:43:51 +02:00
|
|
|
packages.extend(['freeradius3', 'git'])
|
2019-01-30 18:11:18 +01:00
|
|
|
|
2021-06-28 12:19:36 +02:00
|
|
|
if 'gssapi' in features:
|
2021-11-10 21:04:19 +02:00
|
|
|
packages.extend(['krb5', 'krb5-devel'])
|
2022-09-05 22:26:15 +03:00
|
|
|
# FreeBSD comes with a Heimdal krb5-config by default. Make sure
|
|
|
|
# it's deleted so that Kea uses the MIT packages added just above.
|
|
|
|
execute('sudo rm -f /usr/bin/krb5-config')
|
2021-06-28 12:19:36 +02:00
|
|
|
|
2021-02-16 11:50:25 +01:00
|
|
|
if 'ccache' in features:
|
|
|
|
packages.extend(['ccache'])
|
|
|
|
|
2021-08-05 18:12:10 +03:00
|
|
|
if 'netconf' in features:
|
2022-10-07 15:27:08 +03:00
|
|
|
packages.extend(['cmake', 'pcre2'])
|
2021-08-05 18:12:10 +03:00
|
|
|
|
2019-01-29 14:46:07 +01:00
|
|
|
install_pkgs(packages, env=env, timeout=6 * 60, check_times=check_times)
|
2019-01-10 17:36:02 +01:00
|
|
|
|
2021-06-07 14:52:51 +02:00
|
|
|
if 'unittest' in features:
|
|
|
|
_install_gtest_sources()
|
|
|
|
|
2019-01-30 18:11:18 +01:00
|
|
|
if 'mysql' in features:
|
|
|
|
execute('sudo sysrc mysql_enable="yes"', env=env, check_times=check_times)
|
2019-01-31 11:36:38 +01:00
|
|
|
execute('sudo service mysql-server start', env=env, check_times=check_times,
|
|
|
|
raise_error=False)
|
2019-01-30 18:11:18 +01:00
|
|
|
|
2021-06-07 14:52:51 +02:00
|
|
|
execute('sudo pkg clean -a -y')
|
|
|
|
execute('sudo rm -rf /usr/lib/debug')
|
|
|
|
|
2019-09-26 15:20:05 +02:00
|
|
|
# prepare alpine
|
|
|
|
elif system == 'alpine':
|
|
|
|
|
|
|
|
packages = ['gcc', 'g++', 'make', 'autoconf', 'automake', 'libtool', 'openssl-dev',
|
2022-07-22 01:27:39 -07:00
|
|
|
'boost-libs', 'boost-dev', 'procps', 'tar', 'log4cplus', 'log4cplus-dev',
|
|
|
|
'gzip']
|
2019-09-26 15:20:05 +02:00
|
|
|
|
|
|
|
if 'docs' in features:
|
2020-05-15 07:36:04 +02:00
|
|
|
if revision == '3.10':
|
|
|
|
packages.extend(['py-sphinx', 'py-sphinx_rtd_theme'])
|
2020-09-23 17:50:08 +02:00
|
|
|
elif revision == '3.11':
|
2020-05-15 07:36:04 +02:00
|
|
|
packages.extend(['py3-sphinx'])
|
2022-09-05 22:30:57 +03:00
|
|
|
elif float(revision) < 3.16:
|
2020-09-23 17:50:08 +02:00
|
|
|
packages.extend(['py3-sphinx', 'py3-sphinx_rtd_theme'])
|
2022-09-05 22:30:57 +03:00
|
|
|
else:
|
|
|
|
packages.extend(['py3-pip'])
|
2019-09-26 15:20:05 +02:00
|
|
|
|
|
|
|
if 'unittest' in features:
|
|
|
|
_install_gtest_sources()
|
|
|
|
|
2021-08-05 18:12:10 +03:00
|
|
|
if 'netconf' in features:
|
2022-10-07 15:27:08 +03:00
|
|
|
packages.extend(['cmake', 'pcre2-dev'])
|
2021-08-05 18:12:10 +03:00
|
|
|
|
2019-09-26 15:20:05 +02:00
|
|
|
if 'mysql' in features:
|
|
|
|
packages.extend(['mariadb-dev', 'mariadb', 'mariadb-client'])
|
|
|
|
|
|
|
|
if 'pgsql' in features:
|
|
|
|
packages.extend(['postgresql-dev', 'postgresql'])
|
2021-09-11 19:51:55 +03:00
|
|
|
packages.extend(['bison', 'flex', 'boost-dev', 'python3-dev'])
|
2019-09-26 15:20:05 +02:00
|
|
|
|
2021-06-28 12:19:36 +02:00
|
|
|
if 'gssapi' in features:
|
|
|
|
packages.extend(['krb5-dev'])
|
|
|
|
|
2019-09-26 15:20:05 +02:00
|
|
|
if 'native-pkg' in features:
|
|
|
|
packages.extend(['alpine-sdk'])
|
|
|
|
|
2019-10-01 06:12:53 +02:00
|
|
|
if 'ccache' in features:
|
|
|
|
packages.extend(['ccache'])
|
|
|
|
|
2019-09-26 15:20:05 +02:00
|
|
|
install_pkgs(packages, env=env, timeout=6 * 60, check_times=check_times)
|
|
|
|
|
2022-07-26 15:58:37 -07:00
|
|
|
# work around outdated sphinx packages on alpine 3.16
|
2022-09-05 22:30:57 +03:00
|
|
|
if 'docs' in features:
|
|
|
|
if float(revision) >= 3.16:
|
|
|
|
execute('sudo pip3 install -U sphinx sphinx_rtd_theme')
|
2022-07-26 15:58:37 -07:00
|
|
|
|
2020-10-20 14:58:03 +02:00
|
|
|
# check for existence of 'vagrant' user and 'abuild' group before adding him to the group
|
|
|
|
try:
|
|
|
|
pwd.getpwnam('vagrant')
|
|
|
|
grp.getgrnam('abuild')
|
|
|
|
except KeyError:
|
|
|
|
log.info("Can't add 'vagrant' user to 'abuild' group. Vagrant or abuild does not exist.")
|
|
|
|
else:
|
|
|
|
execute('sudo adduser vagrant abuild')
|
|
|
|
|
2021-02-16 11:50:25 +01:00
|
|
|
try:
|
|
|
|
current_user = getpass.getuser()
|
|
|
|
pwd.getpwnam(current_user)
|
|
|
|
grp.getgrnam('abuild')
|
|
|
|
except KeyError:
|
|
|
|
log.info("Can't add %s user to 'abuild' group. %s or abuild does not exist.", current_user, current_user)
|
|
|
|
else:
|
|
|
|
execute('sudo adduser %s abuild' % current_user)
|
|
|
|
|
2018-12-27 15:15:08 +01:00
|
|
|
else:
|
2019-09-26 15:20:05 +02:00
|
|
|
raise NotImplementedError('no implementation for %s' % system)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2022-10-07 15:27:08 +03:00
|
|
|
if 'netconf' in features:
|
|
|
|
_install_netconf_libraries_from_sources('netconf' in ignore_errors_for)
|
|
|
|
|
2021-08-05 18:12:10 +03:00
|
|
|
# Packages required by these functions have been installed. Now call them.
|
|
|
|
for f in deferred_functions:
|
|
|
|
f()
|
|
|
|
|
2019-01-10 17:36:02 +01:00
|
|
|
if 'mysql' in features:
|
2019-01-24 17:54:20 +01:00
|
|
|
_configure_mysql(system, revision, features)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-01-10 17:36:02 +01:00
|
|
|
if 'pgsql' in features:
|
2022-06-13 18:03:32 +02:00
|
|
|
_configure_pgsql(system, features, revision)
|
2019-01-10 17:36:02 +01:00
|
|
|
|
2022-09-05 22:28:01 +03:00
|
|
|
if 'radius' in features:
|
2019-04-10 10:50:15 +02:00
|
|
|
_install_freeradius_client(system, revision, features, env, check_times)
|
2019-01-17 16:41:03 +01:00
|
|
|
|
|
|
|
#execute('sudo rm -rf /usr/share/doc')
|
|
|
|
|
2019-01-24 15:32:03 +01:00
|
|
|
log.info('Preparing deps completed successfully.')
|
|
|
|
|
2019-01-10 17:36:02 +01:00
|
|
|
|
2019-01-31 11:36:38 +01:00
|
|
|
def prepare_system_in_vagrant(provider, system, revision, features, dry_run, check_times,
|
2019-03-14 16:37:12 +01:00
|
|
|
clean_start, ccache_dir=None):
|
2019-01-29 11:30:05 +01:00
|
|
|
"""Prepare specified system in Vagrant according to specified features."""
|
2019-03-14 16:37:12 +01:00
|
|
|
ve = VagrantEnv(provider, system, revision, features, 'kea', dry_run, check_times=check_times,
|
|
|
|
ccache_dir=ccache_dir)
|
2019-01-29 11:30:05 +01:00
|
|
|
if clean_start:
|
|
|
|
ve.destroy()
|
2021-06-07 14:52:51 +02:00
|
|
|
ve.init_files()
|
2019-03-25 09:02:18 +01:00
|
|
|
ve.bring_up_latest_box()
|
2019-01-29 11:30:05 +01:00
|
|
|
ve.prepare_system()
|
|
|
|
|
|
|
|
|
2019-01-30 18:11:18 +01:00
|
|
|
def _calculate_build_timeout(features):
|
2019-01-31 11:36:38 +01:00
|
|
|
"""Return maximum allowed time for build (in seconds)."""
|
2019-01-30 18:11:18 +01:00
|
|
|
timeout = 60
|
|
|
|
if 'mysql' in features:
|
|
|
|
timeout += 60
|
|
|
|
timeout *= 60
|
|
|
|
return timeout
|
|
|
|
|
|
|
|
|
2019-05-14 08:11:34 +02:00
|
|
|
def _prepare_ccache_if_needed(system, ccache_dir, env):
|
|
|
|
if ccache_dir is not None:
|
2019-04-10 10:50:15 +02:00
|
|
|
if system in ['debian', 'ubuntu']:
|
|
|
|
ccache_bin_path = '/usr/lib/ccache/'
|
|
|
|
elif system in ['centos', 'rhel', 'fedora']:
|
|
|
|
ccache_bin_path = '/usr/lib64/ccache'
|
|
|
|
env['CC'] = 'ccache gcc'
|
|
|
|
env['CXX'] = 'ccache g++'
|
2019-10-01 06:12:53 +02:00
|
|
|
elif system == 'alpine':
|
|
|
|
# TODO: it doesn't work yet, new abuild is needed and add 'USE_CCACHE=1' to /etc/abuild.conf
|
|
|
|
ccache_bin_path = '/usr/lib/ccache/bin'
|
2019-04-10 10:50:15 +02:00
|
|
|
env['PATH'] = ccache_bin_path + ':' + env['PATH']
|
|
|
|
env['CCACHE_DIR'] = ccache_dir
|
|
|
|
return env
|
|
|
|
|
|
|
|
|
2019-03-14 16:37:12 +01:00
|
|
|
def _build_binaries_and_run_ut(system, revision, features, tarball_path, env, check_times, jobs, dry_run,
|
|
|
|
ccache_dir):
|
2019-01-29 12:07:09 +01:00
|
|
|
if tarball_path:
|
|
|
|
# unpack tarball with sources
|
2019-01-30 18:11:18 +01:00
|
|
|
execute('sudo rm -rf kea-src')
|
2019-01-29 12:07:09 +01:00
|
|
|
os.mkdir('kea-src')
|
|
|
|
execute('tar -zxf %s' % tarball_path, cwd='kea-src', check_times=check_times)
|
|
|
|
src_path = glob.glob('kea-src/*')[0]
|
|
|
|
else:
|
|
|
|
src_path = '.'
|
|
|
|
|
|
|
|
execute('autoreconf -f -i', cwd=src_path, env=env, dry_run=dry_run)
|
|
|
|
|
|
|
|
# prepare switches for ./configure
|
|
|
|
cmd = './configure'
|
2019-10-14 19:03:46 +07:00
|
|
|
log.info('OS: %s Revision: %s', system, revision)
|
2019-01-29 12:07:09 +01:00
|
|
|
if 'mysql' in features:
|
|
|
|
cmd += ' --with-mysql'
|
|
|
|
if 'pgsql' in features:
|
|
|
|
cmd += ' --with-pgsql'
|
|
|
|
if 'unittest' in features:
|
|
|
|
# prepare gtest switch - use downloaded gtest sources only if it is not present as native package
|
2019-09-26 15:20:05 +02:00
|
|
|
if system in ['centos', 'fedora', 'rhel', 'freebsd', 'alpine']:
|
2021-01-19 19:09:45 +01:00
|
|
|
cmd += ' --with-gtest-source=/usr/src/googletest-release-1.10.0/googletest/'
|
2019-01-31 11:36:38 +01:00
|
|
|
elif system == 'debian' and revision == '8':
|
2021-01-19 19:09:45 +01:00
|
|
|
cmd += ' --with-gtest-source=/usr/src/googletest-release-1.10.0/googletest/'
|
2019-01-31 11:36:38 +01:00
|
|
|
elif system == 'debian':
|
2019-01-29 12:07:09 +01:00
|
|
|
cmd += ' --with-gtest-source=/usr/src/googletest/googletest'
|
2019-01-31 11:36:38 +01:00
|
|
|
elif system == 'ubuntu':
|
2019-01-29 12:07:09 +01:00
|
|
|
if revision.startswith('16.'):
|
2021-01-19 19:09:45 +01:00
|
|
|
cmd += ' --with-gtest-source=/usr/src/googletest-release-1.10.0/googletest/'
|
2019-01-29 12:07:09 +01:00
|
|
|
else:
|
|
|
|
cmd += ' --with-gtest-source=/usr/src/googletest/googletest'
|
2021-11-03 20:08:46 +02:00
|
|
|
elif system == 'arch':
|
|
|
|
pass
|
2019-01-29 12:07:09 +01:00
|
|
|
else:
|
2019-09-26 15:20:05 +02:00
|
|
|
raise NotImplementedError('no implementation for %s' % system)
|
2022-06-13 18:03:32 +02:00
|
|
|
if 'docs' in features and not system == 'rhel':
|
2019-01-29 12:07:09 +01:00
|
|
|
cmd += ' --enable-generate-docs'
|
2022-06-13 18:03:32 +02:00
|
|
|
if system == 'debian' and revision == '8' or system == 'centos' and revision in ['7', '8']:
|
2021-02-16 11:50:25 +01:00
|
|
|
cmd += ' --with-sphinx=~/venv/bin/sphinx-build'
|
2019-01-29 12:07:09 +01:00
|
|
|
if 'radius' in features:
|
|
|
|
cmd += ' --with-freeradius=/usr/local'
|
2021-06-28 12:19:36 +02:00
|
|
|
if 'gssapi' in features:
|
2021-11-10 21:04:19 +02:00
|
|
|
cmd += ' --with-gssapi'
|
2019-01-29 12:07:09 +01:00
|
|
|
if 'shell' in features:
|
|
|
|
cmd += ' --enable-shell'
|
2019-02-19 14:37:00 +01:00
|
|
|
if 'perfdhcp' in features:
|
|
|
|
cmd += ' --enable-perfdhcp'
|
2021-08-05 18:12:10 +03:00
|
|
|
if 'netconf' in features:
|
2022-10-07 15:27:08 +03:00
|
|
|
cmd += ' --with-libyang --with-sysrepo --with-libyang-cpp --with-sysrepo-cpp'
|
2019-01-29 12:07:09 +01:00
|
|
|
|
|
|
|
# do ./configure
|
|
|
|
execute(cmd, cwd=src_path, env=env, timeout=120, check_times=check_times, dry_run=dry_run)
|
|
|
|
|
2021-08-05 18:12:10 +03:00
|
|
|
if 'netconf' in features:
|
|
|
|
# ./configure has created reinstall.sh from reinstall.sh.in. Call it.
|
|
|
|
execute('./src/share/yang/modules/utils/reinstall.sh', cwd=src_path, env=env)
|
|
|
|
|
2019-01-29 12:07:09 +01:00
|
|
|
# estimate number of processes (jobs) to use in compilation if jobs are not provided
|
|
|
|
if jobs == 0:
|
|
|
|
cpus = multiprocessing.cpu_count() - 1
|
2019-01-31 11:36:38 +01:00
|
|
|
if system == 'centos':
|
2019-01-29 12:07:09 +01:00
|
|
|
cpus = cpus // 2
|
|
|
|
if cpus == 0:
|
|
|
|
cpus = 1
|
|
|
|
else:
|
|
|
|
cpus = jobs
|
|
|
|
|
2019-03-14 16:37:12 +01:00
|
|
|
# enable ccache if requested
|
2019-05-14 08:11:34 +02:00
|
|
|
env = _prepare_ccache_if_needed(system, ccache_dir, env)
|
2019-01-30 18:11:18 +01:00
|
|
|
|
2019-01-29 12:07:09 +01:00
|
|
|
# do build
|
2019-01-30 18:11:18 +01:00
|
|
|
timeout = _calculate_build_timeout(features)
|
|
|
|
if 'distcheck' in features:
|
|
|
|
cmd = 'make distcheck'
|
|
|
|
else:
|
2019-09-26 15:20:05 +02:00
|
|
|
cmd = 'make -j%s' % cpus
|
2019-01-30 18:11:18 +01:00
|
|
|
execute(cmd, cwd=src_path, env=env, timeout=timeout, check_times=check_times, dry_run=dry_run)
|
2019-01-29 12:07:09 +01:00
|
|
|
|
|
|
|
if 'unittest' in features:
|
|
|
|
results_dir = os.path.abspath(os.path.join(src_path, 'tests_result'))
|
|
|
|
execute('rm -rf %s' % results_dir, dry_run=dry_run)
|
|
|
|
if not os.path.exists(results_dir):
|
|
|
|
os.mkdir(results_dir)
|
|
|
|
env['GTEST_OUTPUT'] = 'xml:%s/' % results_dir
|
|
|
|
env['KEA_SOCKET_TEST_DIR'] = '/tmp/'
|
|
|
|
# run unit tests
|
2019-01-31 11:36:38 +01:00
|
|
|
execute('make check -k',
|
2019-02-19 14:37:00 +01:00
|
|
|
cwd=src_path, env=env, timeout=90 * 60, raise_error=False,
|
2019-01-31 11:36:38 +01:00
|
|
|
check_times=check_times, dry_run=dry_run)
|
2019-01-29 12:07:09 +01:00
|
|
|
|
|
|
|
# parse unit tests results
|
|
|
|
results = {}
|
|
|
|
grand_total = 0
|
|
|
|
grand_not_passed = 0
|
2019-03-25 09:02:18 +01:00
|
|
|
aggregated_root = ET.Element('testsuites')
|
2019-01-29 12:07:09 +01:00
|
|
|
for fn in os.listdir(results_dir):
|
|
|
|
if not fn.endswith('.xml'):
|
|
|
|
continue
|
|
|
|
fp = os.path.join(results_dir, fn)
|
|
|
|
tree = ET.parse(fp)
|
|
|
|
root = tree.getroot()
|
2019-03-25 09:02:18 +01:00
|
|
|
|
|
|
|
# prepare stats for json
|
2019-01-29 12:07:09 +01:00
|
|
|
total = int(root.get('tests'))
|
|
|
|
failures = int(root.get('failures'))
|
|
|
|
disabled = int(root.get('disabled'))
|
|
|
|
errors = int(root.get('errors'))
|
|
|
|
results[fn] = dict(total=total, failures=failures, disabled=disabled, errors=errors)
|
|
|
|
grand_total += total
|
|
|
|
grand_not_passed += failures + errors
|
|
|
|
|
2021-03-18 10:22:04 +02:00
|
|
|
# append test suites to aggregated root
|
2019-03-25 09:02:18 +01:00
|
|
|
for ts in root.findall('testsuite'):
|
|
|
|
if not ts:
|
|
|
|
continue
|
|
|
|
aggregated_root.append(ts)
|
|
|
|
|
|
|
|
# prepare and stats in json
|
2019-01-29 12:07:09 +01:00
|
|
|
grand_passed = grand_total - grand_not_passed
|
|
|
|
results['grand_passed'] = grand_total - grand_not_passed
|
|
|
|
results['grand_total'] = grand_total
|
|
|
|
|
|
|
|
result = '%s/%s passed' % (grand_passed, grand_total)
|
|
|
|
if grand_not_passed > 0 or grand_total == 0:
|
|
|
|
result = red(result)
|
|
|
|
else:
|
|
|
|
result = green(result)
|
|
|
|
log.info('Unit test results: %s', result)
|
|
|
|
|
|
|
|
with open('unit-test-results.json', 'w') as f:
|
|
|
|
f.write(json.dumps(results))
|
|
|
|
|
2019-03-25 09:02:18 +01:00
|
|
|
# store aggregated results in XML
|
|
|
|
if os.path.exists('aggregated_tests.xml'):
|
|
|
|
os.unlink('aggregated_tests.xml')
|
|
|
|
aggr = ET.ElementTree(aggregated_root)
|
|
|
|
aggr.write('aggregated_tests.xml')
|
|
|
|
|
2019-01-29 12:07:09 +01:00
|
|
|
if 'install' in features:
|
2019-02-19 14:37:00 +01:00
|
|
|
execute('sudo make install', timeout=2 * 60,
|
|
|
|
cwd=src_path, env=env, check_times=check_times, dry_run=dry_run)
|
2022-10-13 14:04:25 +03:00
|
|
|
if system != 'alpine':
|
|
|
|
execute('sudo ldconfig', dry_run=dry_run, env=env)
|
2019-01-29 12:07:09 +01:00
|
|
|
|
|
|
|
if 'forge' in features:
|
|
|
|
if 'mysql' in features:
|
2019-08-30 17:13:04 +02:00
|
|
|
execute('kea-admin db-init mysql -u keauser -p keapass -n keadb', dry_run=dry_run)
|
2019-01-29 12:07:09 +01:00
|
|
|
if 'pgsql' in features:
|
2019-08-30 17:13:04 +02:00
|
|
|
execute('kea-admin db-init pgsql -u keauser -p keapass -n keadb', dry_run=dry_run)
|
2019-01-29 12:07:09 +01:00
|
|
|
|
|
|
|
|
2020-05-29 07:47:04 +02:00
|
|
|
def _check_installed_rpm_or_debs(services_list):
|
|
|
|
for svc in services_list:
|
|
|
|
execute('sudo systemctl stop %s' % svc)
|
2020-05-29 15:25:16 +02:00
|
|
|
now = datetime.datetime.now()
|
|
|
|
timestamp = now.strftime('%Y-%m-%d%H:%M:%S')
|
2020-05-29 07:47:04 +02:00
|
|
|
execute('sudo systemctl start %s' % svc)
|
|
|
|
time.sleep(3)
|
|
|
|
cmd = "sudo journalctl --since %s -u %s | grep '_STARTED Kea'" % (timestamp, svc)
|
2020-05-29 15:25:16 +02:00
|
|
|
execute(cmd, attempts=10, sleep_time_after_attempt=1)
|
2020-05-29 07:47:04 +02:00
|
|
|
|
|
|
|
|
2019-09-26 15:20:05 +02:00
|
|
|
def _build_rpm(system, revision, features, tarball_path, env, check_times, dry_run,
|
|
|
|
pkg_version, pkg_isc_version, repo_url):
|
|
|
|
# install our freeradius-client but now from rpm
|
|
|
|
cmd = 'bash -c "cat <<EOF | sudo tee /etc/yum.repos.d/isc.repo\n'
|
|
|
|
cmd += '[nexus]\n'
|
|
|
|
cmd += 'name=ISC Repo\n'
|
|
|
|
cmd += 'baseurl=%s\n' % repo_url
|
|
|
|
cmd += 'enabled=1\n'
|
|
|
|
cmd += 'gpgcheck=0\n'
|
|
|
|
cmd += "EOF\n\""
|
|
|
|
execute(cmd)
|
|
|
|
if system == 'fedora' and revision == '28':
|
2020-03-18 14:52:25 +01:00
|
|
|
frc_version = 'isc20190916210635.fc28'
|
2019-09-26 15:20:05 +02:00
|
|
|
elif system == 'fedora' and revision == '29':
|
2020-03-18 14:52:25 +01:00
|
|
|
frc_version = 'isc20190916210635.fc29'
|
2019-09-26 15:20:05 +02:00
|
|
|
elif system == 'fedora' and revision == '30':
|
2020-03-18 14:52:25 +01:00
|
|
|
frc_version = 'isc20200318150024.fc30'
|
2019-12-20 09:58:04 +01:00
|
|
|
elif system == 'fedora' and revision == '31':
|
2020-03-18 14:52:25 +01:00
|
|
|
frc_version = 'isc20200318122047.fc31'
|
2020-05-12 11:39:17 +02:00
|
|
|
elif system == 'fedora' and revision == '32':
|
|
|
|
frc_version = 'isc20200511114306.fc32'
|
2021-04-15 10:28:04 +02:00
|
|
|
elif system == 'fedora' and revision == '33':
|
|
|
|
frc_version = 'isc20210415094816.fc33'
|
2021-06-07 14:52:51 +02:00
|
|
|
elif system == 'fedora' and revision == '34':
|
|
|
|
frc_version = 'isc20210528132302.fc34'
|
2022-05-18 09:22:15 +02:00
|
|
|
elif system == 'fedora' and revision == '35':
|
|
|
|
frc_version = 'isc20220516091026.fc35'
|
|
|
|
elif system == 'fedora' and revision == '36':
|
|
|
|
frc_version = 'isc20220516091651.fc36'
|
2023-06-20 16:07:57 +00:00
|
|
|
elif system == 'fedora' and revision == '37':
|
|
|
|
frc_version = 'isc20230620152003.fc37'
|
2023-06-20 22:20:25 +00:00
|
|
|
elif system == 'fedora' and revision == '38':
|
|
|
|
frc_version = 'isc20230621000612.fc38'
|
2019-10-14 19:03:46 +07:00
|
|
|
elif system == 'centos' and revision == '7':
|
2020-03-18 14:52:25 +01:00
|
|
|
frc_version = 'isc20200318122047.el7'
|
2022-05-12 13:48:07 +02:00
|
|
|
elif system in ['centos', 'rhel'] and revision == '8':
|
2020-03-18 14:52:25 +01:00
|
|
|
frc_version = 'isc20200318134606.el8'
|
2022-06-13 18:03:32 +02:00
|
|
|
elif system == 'rhel' and revision == '9':
|
|
|
|
frc_version = 'isc20220613134625.el9'
|
2021-06-07 14:52:51 +02:00
|
|
|
else:
|
|
|
|
raise NotImplementedError('missing freeradius-client version for %s-%s' % (system, revision))
|
|
|
|
|
2022-11-27 14:31:11 +02:00
|
|
|
install_pkgs([
|
|
|
|
f'freeradius-client-1.1.7-{frc_version}',
|
|
|
|
f'freeradius-client-devel-1.1.7-{frc_version}',
|
|
|
|
], env=env, check_times=check_times)
|
2022-07-26 22:01:31 +03:00
|
|
|
|
2022-11-27 14:31:11 +02:00
|
|
|
_append_to_file('freeradius-pkgs.txt', f'freeradius-client-1.1.7-{frc_version}.x86_64.rpm')
|
|
|
|
_append_to_file('freeradius-pkgs.txt', f'freeradius-client-devel-1.1.7-{frc_version}.x86_64.rpm')
|
2019-09-26 15:20:05 +02:00
|
|
|
|
|
|
|
# unpack kea sources tarball
|
|
|
|
execute('sudo rm -rf kea-src', dry_run=dry_run)
|
|
|
|
os.mkdir('kea-src')
|
|
|
|
execute('tar -zxf %s' % tarball_path, cwd='kea-src', check_times=check_times, dry_run=dry_run)
|
|
|
|
src_path = glob.glob('kea-src/*')[0]
|
|
|
|
|
|
|
|
# prepare folder for all pkgs
|
|
|
|
if os.path.exists('pkgs'):
|
|
|
|
execute('rm -rf pkgs')
|
|
|
|
os.mkdir('pkgs')
|
|
|
|
|
|
|
|
# prepare RPM environment
|
2021-02-16 11:50:25 +01:00
|
|
|
rpm_root_path = os.path.expanduser('~/rpm-root')
|
|
|
|
# ensure rm -rf will not wipe out a whole disk
|
|
|
|
if rpm_root_path.endswith("rpm-root"):
|
|
|
|
execute('rm -rf %s' % rpm_root_path)
|
|
|
|
execute('mkdir -p %s/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}' % rpm_root_path)
|
2019-09-26 15:20:05 +02:00
|
|
|
|
|
|
|
# get rpm.spec from tarball
|
|
|
|
rpm_dir = os.path.join(src_path, 'rpm')
|
|
|
|
for f in os.listdir(rpm_dir):
|
|
|
|
if f == 'kea.spec':
|
|
|
|
continue
|
2021-02-16 11:50:25 +01:00
|
|
|
execute('cp %s %s/SOURCES' % (os.path.join(rpm_dir, f), rpm_root_path), check_times=check_times, dry_run=dry_run)
|
|
|
|
execute('cp %s %s/SPECS' % (os.path.join(rpm_dir, 'kea.spec'), rpm_root_path), check_times=check_times, dry_run=dry_run)
|
|
|
|
execute('cp %s %s/SOURCES' % (tarball_path, rpm_root_path), check_times=check_times, dry_run=dry_run)
|
2019-04-10 10:50:15 +02:00
|
|
|
|
2021-02-16 11:50:25 +01:00
|
|
|
execute('sed -i -e s/{FREERADIUS_CLIENT_VERSION}/%s/g %s/SPECS/kea.spec' % (frc_version, rpm_root_path), check_times=check_times, dry_run=dry_run)
|
2020-03-18 14:52:25 +01:00
|
|
|
|
2023-09-21 11:23:12 +00:00
|
|
|
services_list = ['kea-dhcp4.service', 'kea-dhcp6.service', 'kea-dhcp-ddns.service', 'kea-ctrl-agent.service']
|
|
|
|
|
|
|
|
# centos/rhel 7 does not support some fields in systemd unit files so they need to be commented out
|
|
|
|
if system == 'centos' and revision == '7':
|
|
|
|
for f in services_list:
|
|
|
|
for k in ['RuntimeDirectory', 'RuntimeDirectoryPreserve', 'LogsDirectory', 'LogsDirectoryMode', 'StateDirectory', 'ConfigurationDirectory']:
|
|
|
|
cmd = "sed -i -E 's/^(%s=.*)/#\\1/' %s" % (k, f)
|
|
|
|
execute(cmd, cwd=rpm_dir, check_times=check_times, dry_run=dry_run)
|
|
|
|
|
|
|
|
|
2019-09-26 15:20:05 +02:00
|
|
|
# do rpm build
|
2021-02-16 11:50:25 +01:00
|
|
|
cmd = "rpmbuild --define 'kea_version %s' --define 'isc_version %s' -ba %s/SPECS/kea.spec"
|
|
|
|
cmd += " -D'_topdir %s'"
|
2019-09-26 15:20:05 +02:00
|
|
|
cmd += " --undefine=_debugsource_packages" # disable creating debugsource package
|
2021-02-16 11:50:25 +01:00
|
|
|
cmd = cmd % (pkg_version, pkg_isc_version, rpm_root_path, rpm_root_path)
|
2019-09-26 15:20:05 +02:00
|
|
|
execute(cmd, env=env, timeout=60 * 40, check_times=check_times, dry_run=dry_run)
|
2019-04-10 10:50:15 +02:00
|
|
|
|
2019-09-26 15:20:05 +02:00
|
|
|
if 'install' in features:
|
2020-05-29 07:47:04 +02:00
|
|
|
# install packages
|
2019-09-26 15:20:05 +02:00
|
|
|
execute('rpm -qa | grep isc-kea | xargs sudo rpm -e', check_times=check_times, dry_run=dry_run, raise_error=False)
|
2021-03-26 15:11:53 +01:00
|
|
|
execute('sudo rpm -i %s/RPMS/x86_64/*rpm' % rpm_root_path, check_times=check_times, dry_run=dry_run)
|
2019-04-10 10:50:15 +02:00
|
|
|
|
2020-05-29 07:47:04 +02:00
|
|
|
# check if kea services can be started
|
|
|
|
services_list = ['kea-dhcp4.service', 'kea-dhcp6.service', 'kea-dhcp-ddns.service', 'kea-ctrl-agent.service']
|
|
|
|
_check_installed_rpm_or_debs(services_list)
|
|
|
|
|
2021-02-16 11:50:25 +01:00
|
|
|
execute('mv %s/RPMS/x86_64/*rpm pkgs' % rpm_root_path, check_times=check_times, dry_run=dry_run)
|
2019-04-10 10:50:15 +02:00
|
|
|
|
|
|
|
|
2019-09-26 15:20:05 +02:00
|
|
|
def _build_deb(system, revision, features, tarball_path, env, check_times, dry_run,
|
2019-10-16 13:42:07 +07:00
|
|
|
pkg_version, pkg_isc_version, repository_url, repo_url):
|
2019-09-26 15:20:05 +02:00
|
|
|
if system == 'debian' and revision == '9':
|
|
|
|
# debian 9 does not support apt-installing over https, so install proper transport
|
|
|
|
install_pkgs('apt-transport-https', env=env, check_times=check_times)
|
2022-09-06 16:38:44 +03:00
|
|
|
|
|
|
|
# See if a .deb package had been previously uploaded.
|
|
|
|
_, output = execute("curl -o /dev/null -s -w '%{{http_code}}' {}/dists/kea/Release 2>/dev/null".format(repo_url), capture=True)
|
|
|
|
http_code = output.rstrip()
|
|
|
|
release_file_exists = (http_code == '200')
|
|
|
|
if release_file_exists:
|
|
|
|
log.info(f'{repo_url}/dists/kea/Release exists.')
|
|
|
|
else:
|
|
|
|
repo_name = 'kea-%s-%s-%s' % (pkg_version.rsplit('.', 1)[0], system, revision)
|
|
|
|
log.error(f'{repo_url}/dists/kea/Release does not exist. '
|
|
|
|
f'This is usually caused by no package existing in {repo_name}. '
|
|
|
|
'You can solve this by uploading the freeradius-client packages '
|
|
|
|
'which are also needed further to build packages. '
|
|
|
|
'Continuing, but the build will likely fail.')
|
|
|
|
|
2019-09-26 15:20:05 +02:00
|
|
|
# install our freeradius-client but now from deb
|
|
|
|
execute("echo 'deb %s kea main' | sudo tee /etc/apt/sources.list.d/isc.list" % repo_url)
|
|
|
|
key_url = "%s/repository/repo-keys/repo-key.gpg" % repository_url
|
|
|
|
execute('wget -qO- %s | sudo apt-key add -' % key_url,
|
|
|
|
env=env, check_times=check_times)
|
2022-09-06 16:38:44 +03:00
|
|
|
|
2019-09-26 15:20:05 +02:00
|
|
|
# try apt update for up to 10 times if there is an error
|
|
|
|
for _ in range(10):
|
|
|
|
_, out = _apt_update(system, revision, capture=True)
|
|
|
|
if 'Bad header data' not in out:
|
|
|
|
break
|
|
|
|
time.sleep(4)
|
2021-06-09 13:03:07 +02:00
|
|
|
if system == 'debian' or (system == 'ubuntu' and revision == '18.04'):
|
|
|
|
frc_version = 'isc20200318122047'
|
|
|
|
elif system == 'ubuntu' and revision == '19.04':
|
2020-03-18 14:52:25 +01:00
|
|
|
frc_version = 'isc20200319090824'
|
2020-05-12 11:39:17 +02:00
|
|
|
elif system == 'ubuntu' and revision == '20.04':
|
|
|
|
frc_version = 'isc20200511114306'
|
2021-04-19 16:02:31 +02:00
|
|
|
elif system == 'ubuntu' and revision == '20.10':
|
|
|
|
frc_version = 'isc20210419151920'
|
2021-06-07 14:52:51 +02:00
|
|
|
elif system == 'ubuntu' and revision == '21.04':
|
|
|
|
frc_version = 'isc20210528123038'
|
2022-06-08 17:46:33 +02:00
|
|
|
elif system == 'ubuntu' and revision == '22.04':
|
|
|
|
frc_version = 'isc20220608134906'
|
2020-03-18 14:52:25 +01:00
|
|
|
else:
|
2021-06-07 14:52:51 +02:00
|
|
|
raise NotImplementedError('missing freeradius-client version for %s-%s' % (system, revision))
|
|
|
|
|
2022-11-27 14:31:11 +02:00
|
|
|
install_pkgs([
|
|
|
|
f'libfreeradius-client=1.1.7-{frc_version}',
|
|
|
|
f'libfreeradius-client-dev=1.1.7-{frc_version}',
|
|
|
|
], env=env, check_times=check_times)
|
2022-07-26 22:01:31 +03:00
|
|
|
|
2022-11-27 14:31:11 +02:00
|
|
|
_append_to_file('freeradius-pkgs.txt', f'libfreeradius-client_1.1.7-{frc_version}_amd64.deb')
|
|
|
|
_append_to_file('freeradius-pkgs.txt', f'libfreeradius-client-dev_1.1.7-{frc_version}_amd64.deb')
|
2019-01-29 12:07:09 +01:00
|
|
|
|
2019-09-26 15:20:05 +02:00
|
|
|
# unpack tarball
|
|
|
|
execute('sudo rm -rf kea-src', check_times=check_times, dry_run=dry_run)
|
|
|
|
os.mkdir('kea-src')
|
|
|
|
execute('tar -zxf %s' % tarball_path, cwd='kea-src', check_times=check_times, dry_run=dry_run)
|
|
|
|
src_path = glob.glob('kea-src/*')[0]
|
2019-01-29 12:07:09 +01:00
|
|
|
|
2019-09-26 15:20:05 +02:00
|
|
|
# update version, etc
|
|
|
|
execute('sed -i -e s/{VERSION}/%s/ changelog' % pkg_version, cwd='kea-src/kea-%s/debian' % pkg_version, check_times=check_times, dry_run=dry_run)
|
|
|
|
execute('sed -i -e s/{ISC_VERSION}/%s/ changelog' % pkg_isc_version, cwd='kea-src/kea-%s/debian' % pkg_version, check_times=check_times, dry_run=dry_run)
|
2023-10-03 18:34:33 +02:00
|
|
|
execute('sed -i -e s/{ISC_VERSION}/%s/ rules' % pkg_isc_version, cwd='kea-src/kea-%s/debian' % pkg_version, check_times=check_times, dry_run=dry_run)
|
2020-03-18 14:52:25 +01:00
|
|
|
execute('sed -i -e s/{FREERADIUS_CLIENT_VERSION}/%s/g control' % frc_version, cwd='kea-src/kea-%s/debian' % pkg_version, check_times=check_times, dry_run=dry_run)
|
2019-01-29 12:07:09 +01:00
|
|
|
|
2023-09-21 11:23:12 +00:00
|
|
|
services_list = ['isc-kea-dhcp4.isc-kea-dhcp4-server.service', 'isc-kea-dhcp6.isc-kea-dhcp6-server.service', 'isc-kea-dhcp-ddns.isc-kea-dhcp-ddns-server.service', 'isc-kea-ctrl-agent.service']
|
2020-05-29 07:47:04 +02:00
|
|
|
|
|
|
|
# debian 9 does not support some fields in systemd unit files so they need to be commented out
|
|
|
|
if system == 'debian' and revision == '9':
|
|
|
|
for f in services_list:
|
|
|
|
for k in ['RuntimeDirectory', 'RuntimeDirectoryPreserve', 'LogsDirectory', 'LogsDirectoryMode', 'StateDirectory', 'ConfigurationDirectory']:
|
|
|
|
cmd = "sed -i -E 's/^(%s=.*)/#\\1/' %s" % (k, f)
|
|
|
|
execute(cmd, cwd='kea-src/kea-%s/debian' % pkg_version, check_times=check_times, dry_run=dry_run)
|
|
|
|
|
2019-09-26 15:20:05 +02:00
|
|
|
# do deb build
|
|
|
|
env['LIBRARY_PATH'] = '/usr/lib/x86_64-linux-gnu'
|
|
|
|
env['LD_LIBRARY_PATH'] = '/usr/lib/x86_64-linux-gnu'
|
|
|
|
cmd = 'debuild --preserve-envvar=LD_LIBRARY_PATH --preserve-envvar=LIBRARY_PATH --preserve-envvar=CCACHE_DIR --prepend-path=/usr/lib/ccache -i -us -uc -b'
|
|
|
|
execute(cmd, env=env, cwd=src_path, timeout=60 * 40, check_times=check_times, dry_run=dry_run)
|
2019-04-10 10:50:15 +02:00
|
|
|
|
2019-09-26 15:20:05 +02:00
|
|
|
if 'install' in features:
|
2020-05-29 07:47:04 +02:00
|
|
|
# install packages
|
2019-09-26 15:20:05 +02:00
|
|
|
execute('sudo dpkg -i kea-src/*deb', check_times=check_times, dry_run=dry_run)
|
2020-05-29 07:47:04 +02:00
|
|
|
# check if kea services can be started
|
2023-09-21 11:23:12 +00:00
|
|
|
services_list = ['isc-kea-dhcp4-server.service', 'isc-kea-dhcp6-server.service', 'isc-kea-dhcp-ddns-server.service', 'isc-kea-ctrl-agent.service']
|
2020-05-29 07:47:04 +02:00
|
|
|
_check_installed_rpm_or_debs(services_list)
|
2019-09-26 15:20:05 +02:00
|
|
|
|
|
|
|
|
|
|
|
def _build_alpine_apk(system, revision, features, tarball_path, env, check_times, dry_run,
|
|
|
|
pkg_version, pkg_isc_version, repo_url):
|
|
|
|
# unpack tarball
|
|
|
|
execute('sudo rm -rf kea-src packages', check_times=check_times, dry_run=dry_run)
|
|
|
|
os.makedirs('kea-src/src')
|
|
|
|
execute('tar -zxf %s' % tarball_path, check_times=check_times, dry_run=dry_run)
|
2020-05-15 07:36:04 +02:00
|
|
|
if revision == '3.10':
|
|
|
|
sys_suffix = '-3.10'
|
|
|
|
else:
|
|
|
|
sys_suffix = ''
|
|
|
|
execute('mv kea-%s/alpine%s/* kea-src' % (pkg_version, sys_suffix), check_times=check_times, dry_run=dry_run)
|
2019-09-26 15:20:05 +02:00
|
|
|
execute('rm -rf kea-%s' % pkg_version, check_times=check_times, dry_run=dry_run)
|
2021-06-07 14:52:51 +02:00
|
|
|
tardir = os.path.dirname(tarball_path)
|
|
|
|
if not tardir:
|
|
|
|
tardir = '.'
|
|
|
|
cmd = 'cd %s; export kea_chks=`sha512sum kea-%s.tar.gz`; cd -; sed -i -e "s/KEA_CHECKSUM/${kea_chks}/" kea-src/APKBUILD' % (tardir, pkg_version)
|
2019-09-26 15:20:05 +02:00
|
|
|
execute(cmd, check_times=check_times, dry_run=dry_run)
|
|
|
|
cmd = 'sed -i -e s/KEA_VERSION/%s/ kea-src/APKBUILD' % pkg_version
|
|
|
|
execute(cmd, check_times=check_times, dry_run=dry_run)
|
2021-06-07 14:52:51 +02:00
|
|
|
cmd = 'sed -i -e s/KEA_ISC_VERSION/%s/ kea-src/APKBUILD' % pkg_isc_version[3:]
|
2019-09-26 15:20:05 +02:00
|
|
|
execute(cmd, check_times=check_times, dry_run=dry_run)
|
2021-02-16 11:50:25 +01:00
|
|
|
log.info('Moving %s to kea-src folder', tarball_path)
|
|
|
|
execute('mv %s kea-src' % tarball_path, check_times=check_times, dry_run=dry_run)
|
2019-09-26 15:20:05 +02:00
|
|
|
execute('abuild-keygen -n -a -i', check_times=check_times, dry_run=dry_run)
|
|
|
|
execute('abuild -v -r', cwd='kea-src', check_times=check_times, dry_run=dry_run)
|
2021-06-07 14:52:51 +02:00
|
|
|
|
2021-06-09 13:03:07 +02:00
|
|
|
# copy packages from alpine specific dir with produced pkgs to common place
|
|
|
|
alpine_repo_dir = os.path.basename(os.getcwd())
|
|
|
|
src_dir = '~/packages/%s/x86_64' % alpine_repo_dir
|
2021-06-07 14:52:51 +02:00
|
|
|
execute('cp %s/*.apk kea-pkg' % src_dir, check_times=check_times, dry_run=dry_run)
|
2019-04-10 10:50:15 +02:00
|
|
|
|
2019-09-26 15:20:05 +02:00
|
|
|
if 'install' in features:
|
2020-05-29 07:47:04 +02:00
|
|
|
# install packages
|
2021-02-16 11:50:25 +01:00
|
|
|
execute('sudo apk add *.apk', cwd='kea-pkg', check_times=check_times, dry_run=dry_run)
|
2019-09-26 15:20:05 +02:00
|
|
|
|
2020-05-29 07:47:04 +02:00
|
|
|
# check if kea services can be started
|
|
|
|
for svc in ['kea-dhcp4', 'kea-dhcp6', 'kea-ctrl-agent', 'kea-dhcp-ddns']:
|
|
|
|
execute('sudo rc-service %s start' % svc)
|
|
|
|
time.sleep(3)
|
|
|
|
if svc == 'kea-dhcp-ddns':
|
|
|
|
svc = 'kea-ddns'
|
2020-05-29 15:25:16 +02:00
|
|
|
log_path = '/var/log/kea/%s.log' % svc
|
|
|
|
if revision == '3.10':
|
|
|
|
log_path = '/var/log/%s.log' % svc
|
|
|
|
cmd = "sudo cat %s | grep '_STARTED Kea'" % log_path
|
|
|
|
execute(cmd, attempts=10, sleep_time_after_attempt=1)
|
2020-05-29 07:47:04 +02:00
|
|
|
|
|
|
|
|
2019-09-26 15:20:05 +02:00
|
|
|
def _build_native_pkg(system, revision, features, tarball_path, env, check_times, dry_run, ccache_dir,
|
2021-02-16 11:50:25 +01:00
|
|
|
pkg_version, pkg_isc_version, repository_url, pkgs_dir):
|
2019-09-26 15:20:05 +02:00
|
|
|
"""Build native (RPM or DEB or Alpine APK) packages."""
|
|
|
|
|
|
|
|
# enable ccache if requested
|
|
|
|
env = _prepare_ccache_if_needed(system, ccache_dir, env)
|
2019-01-29 12:07:09 +01:00
|
|
|
|
2019-09-26 15:20:05 +02:00
|
|
|
repo_url = _get_full_repo_url(repository_url, system, revision, pkg_version)
|
|
|
|
assert repo_url is not None
|
2019-04-10 10:50:15 +02:00
|
|
|
|
2019-09-26 15:20:05 +02:00
|
|
|
if system in ['fedora', 'centos', 'rhel']:
|
|
|
|
_build_rpm(system, revision, features, tarball_path, env, check_times, dry_run,
|
|
|
|
pkg_version, pkg_isc_version, repo_url)
|
2019-01-29 12:07:09 +01:00
|
|
|
|
2019-09-26 15:20:05 +02:00
|
|
|
elif system in ['ubuntu', 'debian']:
|
|
|
|
_build_deb(system, revision, features, tarball_path, env, check_times, dry_run,
|
2019-10-16 13:42:07 +07:00
|
|
|
pkg_version, pkg_isc_version, repository_url, repo_url)
|
2019-09-26 15:20:05 +02:00
|
|
|
|
|
|
|
elif system in ['alpine']:
|
|
|
|
_build_alpine_apk(system, revision, features, tarball_path, env, check_times, dry_run,
|
|
|
|
pkg_version, pkg_isc_version, repo_url)
|
2019-01-29 12:07:09 +01:00
|
|
|
|
2021-11-03 20:08:46 +02:00
|
|
|
elif system in ['arch']:
|
|
|
|
pass
|
|
|
|
|
2019-01-29 12:07:09 +01:00
|
|
|
else:
|
2019-09-26 15:20:05 +02:00
|
|
|
raise NotImplementedError('no implementation for %s' % system)
|
2019-01-29 12:07:09 +01:00
|
|
|
|
2021-02-16 11:50:25 +01:00
|
|
|
if system in ['ubuntu', 'debian']:
|
|
|
|
execute('mv kea-src/isc-kea_* %s' % pkgs_dir)
|
|
|
|
execute('mv kea-src/*deb %s' % pkgs_dir)
|
|
|
|
elif system in ['fedora', 'centos', 'rhel']:
|
|
|
|
execute('mv pkgs/* %s' % pkgs_dir)
|
|
|
|
elif system in ['alpine']:
|
|
|
|
#execute('mv kea-src/* %s' % pkgs_dir)
|
|
|
|
execute('mv kea-pkg/* %s' % pkgs_dir)
|
2021-11-03 20:08:46 +02:00
|
|
|
elif system in ['arch']:
|
|
|
|
pass
|
2021-02-16 11:50:25 +01:00
|
|
|
else:
|
2022-03-11 16:38:50 +02:00
|
|
|
raise NotImplementedError('no implementation for %s' % system)
|
2021-02-16 11:50:25 +01:00
|
|
|
|
2019-01-29 12:07:09 +01:00
|
|
|
|
2019-04-10 10:50:15 +02:00
|
|
|
def build_local(features, tarball_path, check_times, jobs, dry_run, ccache_dir, pkg_version, pkg_isc_version,
|
2021-02-16 11:50:25 +01:00
|
|
|
repository_url, pkgs_dir):
|
2019-01-29 11:30:05 +01:00
|
|
|
"""Prepare local system for Kea development based on requested features.
|
|
|
|
|
|
|
|
If tarball_path is provided then instead of Kea sources from current directory
|
|
|
|
use provided tarball.
|
|
|
|
"""
|
2018-12-27 15:15:08 +01:00
|
|
|
env = os.environ.copy()
|
|
|
|
env['LANGUAGE'] = env['LANG'] = env['LC_ALL'] = 'C'
|
|
|
|
|
2019-01-31 11:36:38 +01:00
|
|
|
system, revision = get_system_revision()
|
2019-06-24 21:58:48 +02:00
|
|
|
log.info('Building for %s %s', system, revision)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2021-02-16 11:50:25 +01:00
|
|
|
execute('sudo df -h', dry_run=dry_run)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2021-02-16 11:50:25 +01:00
|
|
|
# NOTE: the old code expects having tarball in tarball_path
|
|
|
|
if not tarball_path:
|
|
|
|
name_ver = 'kea-%s' % pkg_version
|
|
|
|
cmd = 'tar --transform "flags=r;s|^|%s/|" --exclude hammer ' % name_ver
|
|
|
|
cmd += ' --exclude "*~" --exclude .git --exclude .libs '
|
|
|
|
cmd += ' --exclude .deps --exclude \'*.o\' --exclude \'*.lo\' '
|
|
|
|
cmd += ' -zcf /tmp/%s.tar.gz .' % name_ver
|
|
|
|
execute(cmd)
|
|
|
|
tarball_path = '/tmp/%s.tar.gz' % name_ver
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
if 'native-pkg' in features:
|
2019-04-10 10:50:15 +02:00
|
|
|
_build_native_pkg(system, revision, features, tarball_path, env, check_times, dry_run, ccache_dir,
|
2021-02-16 11:50:25 +01:00
|
|
|
pkg_version, pkg_isc_version, repository_url, pkgs_dir)
|
2018-12-27 15:15:08 +01:00
|
|
|
else:
|
2019-03-14 16:37:12 +01:00
|
|
|
_build_binaries_and_run_ut(system, revision, features, tarball_path, env, check_times, jobs,
|
|
|
|
dry_run, ccache_dir)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2021-02-16 11:50:25 +01:00
|
|
|
execute('sudo df -h', dry_run=dry_run)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
|
2019-01-31 11:36:38 +01:00
|
|
|
def build_in_vagrant(provider, system, revision, features, leave_system, tarball_path,
|
2019-04-10 10:50:15 +02:00
|
|
|
dry_run, quiet, clean_start, check_times, jobs, ccache_dir,
|
|
|
|
pkg_version, pkg_isc_version, upload, repository_url):
|
2019-01-29 11:30:05 +01:00
|
|
|
"""Build Kea via Vagrant in specified system with specified features."""
|
2018-12-27 15:15:08 +01:00
|
|
|
log.info('')
|
2019-01-31 11:36:38 +01:00
|
|
|
log.info(">>> Building %s, %s, %s", provider, system, revision)
|
2018-12-27 15:15:08 +01:00
|
|
|
log.info('')
|
|
|
|
|
|
|
|
t0 = time.time()
|
|
|
|
|
2019-01-22 15:48:34 +01:00
|
|
|
ve = None
|
2019-01-10 17:36:02 +01:00
|
|
|
error = None
|
|
|
|
total = 0
|
|
|
|
passed = 0
|
2018-12-27 15:15:08 +01:00
|
|
|
try:
|
2019-03-14 16:37:12 +01:00
|
|
|
ve = VagrantEnv(provider, system, revision, features, 'kea', dry_run, quiet, check_times,
|
|
|
|
ccache_dir)
|
2019-01-10 17:36:02 +01:00
|
|
|
if clean_start:
|
2019-01-25 16:08:12 +01:00
|
|
|
ve.destroy()
|
2021-06-07 14:52:51 +02:00
|
|
|
ve.init_files()
|
2019-03-25 09:02:18 +01:00
|
|
|
ve.bring_up_latest_box()
|
2019-01-25 16:08:12 +01:00
|
|
|
ve.prepare_system()
|
2019-04-10 10:50:15 +02:00
|
|
|
total, passed = ve.run_build_and_test(tarball_path, jobs, pkg_version, pkg_isc_version, upload, repository_url)
|
2019-01-10 17:36:02 +01:00
|
|
|
msg = ' - ' + green('all ok')
|
|
|
|
except KeyboardInterrupt as e:
|
|
|
|
error = e
|
|
|
|
msg = ' - keyboard interrupt'
|
|
|
|
except ExecutionError as e:
|
|
|
|
error = e
|
|
|
|
msg = ' - ' + red(str(e))
|
2019-01-29 12:07:09 +01:00
|
|
|
except Exception as e: # pylint: disable=broad-except
|
2019-01-10 17:36:02 +01:00
|
|
|
log.exception('Building erred')
|
|
|
|
error = e
|
|
|
|
msg = ' - ' + red(str(e))
|
|
|
|
finally:
|
2019-01-22 15:48:34 +01:00
|
|
|
if not leave_system and ve:
|
2019-01-25 16:08:12 +01:00
|
|
|
ve.destroy()
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
t1 = time.time()
|
|
|
|
dt = int(t1 - t0)
|
|
|
|
|
|
|
|
log.info('')
|
2019-01-31 11:36:38 +01:00
|
|
|
log.info(">>> Building %s, %s, %s completed in %s:%s%s", provider, system, revision, dt // 60, dt % 60, msg)
|
2018-12-27 15:15:08 +01:00
|
|
|
log.info('')
|
|
|
|
|
2019-01-10 17:36:02 +01:00
|
|
|
return dt, error, total, passed
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
|
2021-03-15 09:54:46 +01:00
|
|
|
def package_box(provider, system, revision, features, dry_run, check_times, reuse, skip_upload):
|
2019-01-29 11:30:05 +01:00
|
|
|
"""Prepare Vagrant box of specified system."""
|
2019-01-31 11:36:38 +01:00
|
|
|
ve = VagrantEnv(provider, system, revision, features, 'bare', dry_run, check_times=check_times)
|
2019-05-14 08:11:34 +02:00
|
|
|
if not reuse:
|
|
|
|
ve.destroy()
|
2021-06-07 14:52:51 +02:00
|
|
|
ve.init_files()
|
2019-03-25 09:02:18 +01:00
|
|
|
ve.bring_up_latest_box()
|
2019-01-25 16:08:12 +01:00
|
|
|
ve.prepare_system()
|
2021-03-15 09:54:46 +01:00
|
|
|
ve.prepare_for_boxing()
|
2019-03-25 09:02:18 +01:00
|
|
|
box_path = ve.package()
|
2021-03-15 09:54:46 +01:00
|
|
|
if not skip_upload:
|
|
|
|
ve.upload_to_cloud(box_path)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
|
2019-01-31 11:36:38 +01:00
|
|
|
def ssh(provider, system, revision):
|
|
|
|
"""Invoke Vagrant ssh for given system."""
|
|
|
|
ve = VagrantEnv(provider, system, revision, [], 'kea', False)
|
2018-12-27 15:15:08 +01:00
|
|
|
ve.up()
|
|
|
|
ve.ssh()
|
|
|
|
|
|
|
|
|
2021-11-03 19:50:49 +02:00
|
|
|
def _install_vagrant(ver=RECOMMENDED_VAGRANT_VERSION, upgrade=False):
|
2019-01-31 11:36:38 +01:00
|
|
|
system, _ = get_system_revision()
|
2019-03-04 11:36:57 +01:00
|
|
|
if system in ['fedora', 'centos', 'rhel']:
|
|
|
|
if upgrade:
|
2021-11-03 19:50:49 +02:00
|
|
|
execute('sudo yum remove -y vagrant')
|
2022-11-29 20:59:19 +02:00
|
|
|
execute('mkdir -p ~/.hammer-tmp')
|
2019-03-04 11:36:57 +01:00
|
|
|
rpm = 'vagrant_%s_x86_64.rpm' % ver
|
2022-11-29 20:59:19 +02:00
|
|
|
cmd = 'wget --no-verbose -O ~/.hammer-tmp/%s ' % rpm
|
2019-03-04 11:36:57 +01:00
|
|
|
cmd += 'https://releases.hashicorp.com/vagrant/%s/%s' % (ver, rpm)
|
|
|
|
execute(cmd)
|
2022-11-29 20:59:19 +02:00
|
|
|
execute('sudo rpm -i ~/.hammer-tmp/%s' % rpm)
|
|
|
|
execute('rm -rf ~/.hammer-tmp')
|
2019-03-04 11:36:57 +01:00
|
|
|
elif system in ['debian', 'ubuntu']:
|
|
|
|
if upgrade:
|
2021-11-03 19:50:49 +02:00
|
|
|
execute('sudo apt-get purge -y vagrant')
|
2022-11-29 20:59:19 +02:00
|
|
|
execute('mkdir -p ~/.hammer-tmp')
|
2019-03-04 11:36:57 +01:00
|
|
|
deb = 'vagrant_%s_x86_64.deb' % ver
|
2022-11-29 20:59:19 +02:00
|
|
|
cmd = 'wget --no-verbose -O ~/.hammer-tmp/%s ' % deb
|
2019-03-04 11:36:57 +01:00
|
|
|
cmd += 'https://releases.hashicorp.com/vagrant/%s/%s' % (ver, deb)
|
|
|
|
execute(cmd)
|
2022-11-29 20:59:19 +02:00
|
|
|
execute('sudo dpkg -i ~/.hammer-tmp/%s' % deb)
|
|
|
|
execute('rm -rf ~/.hammer-tmp')
|
2021-11-03 20:08:46 +02:00
|
|
|
elif system in ['arch']:
|
|
|
|
pass
|
2019-03-04 11:36:57 +01:00
|
|
|
else:
|
|
|
|
# TODO: check for packages here: https://www.vagrantup.com/downloads.html
|
2019-09-26 15:20:05 +02:00
|
|
|
raise NotImplementedError('no implementation for %s' % system)
|
2019-03-04 11:36:57 +01:00
|
|
|
|
2019-01-10 17:36:02 +01:00
|
|
|
|
2019-03-04 11:36:57 +01:00
|
|
|
def ensure_hammer_deps():
|
|
|
|
"""Install Hammer dependencies onto current, host system."""
|
|
|
|
exitcode, out = execute('vagrant version', raise_error=False, capture=True)
|
2019-01-10 17:36:02 +01:00
|
|
|
if exitcode != 0:
|
2019-03-04 11:36:57 +01:00
|
|
|
_install_vagrant()
|
|
|
|
else:
|
|
|
|
m = re.search('Installed Version: ([\d\.]+)', out, re.I)
|
|
|
|
ver = m.group(1)
|
2021-11-03 19:50:49 +02:00
|
|
|
vagrant = [int(v) for v in ver.split('.')]
|
|
|
|
recommended_vagrant = [int(v) for v in RECOMMENDED_VAGRANT_VERSION.split('.')]
|
|
|
|
if vagrant < recommended_vagrant:
|
2019-03-04 11:36:57 +01:00
|
|
|
m = re.search('Latest Version: ([\d\.]+)', out, re.I)
|
2021-11-03 19:50:49 +02:00
|
|
|
if m is None:
|
|
|
|
# Vagrant was unable to check for the latest version of Vagrant.
|
|
|
|
# Attempt to upgrade to the recommended version to fix it.
|
|
|
|
_install_vagrant(upgrade=True)
|
|
|
|
return
|
2019-03-04 11:36:57 +01:00
|
|
|
ver = m.group(1)
|
|
|
|
_install_vagrant(ver, upgrade=True)
|
|
|
|
|
2019-01-10 17:36:02 +01:00
|
|
|
|
|
|
|
exitcode = execute('vagrant plugin list | grep vagrant-lxc', raise_error=False)
|
|
|
|
if exitcode != 0:
|
|
|
|
execute('vagrant plugin install vagrant-lxc')
|
2021-09-06 20:32:08 +03:00
|
|
|
|
|
|
|
# Install lxc-create.
|
2021-02-16 11:50:25 +01:00
|
|
|
system, _ = get_system_revision()
|
2021-09-06 20:32:08 +03:00
|
|
|
if system == 'debian':
|
|
|
|
execute('sudo apt-get -y install lxc')
|
2021-02-16 11:50:25 +01:00
|
|
|
if system in ['ubuntu']:
|
|
|
|
execute('sudo apt-get -y install lxc-utils')
|
2019-01-10 17:36:02 +01:00
|
|
|
|
|
|
|
|
2019-01-28 12:16:33 +01:00
|
|
|
class CollectCommaSeparatedArgsAction(argparse.Action):
|
2019-01-29 11:30:05 +01:00
|
|
|
"""Helper argparse action class that can split multi-argument options by space and by comma."""
|
|
|
|
|
2019-01-28 12:16:33 +01:00
|
|
|
def __call__(self, parser, namespace, values, option_string=None):
|
|
|
|
values2 = []
|
|
|
|
for v1 in values:
|
|
|
|
for v2 in v1.split():
|
|
|
|
values2.extend(v2.split(','))
|
|
|
|
|
|
|
|
for v in values2:
|
|
|
|
if v not in ALL_FEATURES:
|
2019-01-31 11:36:38 +01:00
|
|
|
msg = "feature '%s' is not supported. List of supported features: %s."
|
|
|
|
msg = msg % (v, ", ".join(ALL_FEATURES))
|
|
|
|
raise argparse.ArgumentError(self, msg)
|
2019-01-28 12:16:33 +01:00
|
|
|
|
|
|
|
setattr(namespace, self.dest, values2)
|
|
|
|
|
|
|
|
|
2022-03-11 16:38:50 +02:00
|
|
|
DEFAULT_FEATURES = ['docs', 'install', 'perfdhcp', 'unittest']
|
|
|
|
ALL_FEATURES = ['all', 'ccache', 'distcheck', 'docs', 'forge', 'gssapi',
|
|
|
|
'install', 'mysql', 'native-pkg', 'netconf', 'perfdhcp',
|
|
|
|
'pgsql', 'radius', 'shell', 'tls', 'unittest']
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-01-29 12:07:09 +01:00
|
|
|
|
2018-12-27 15:15:08 +01:00
|
|
|
def parse_args():
|
2019-01-31 11:36:38 +01:00
|
|
|
"""Parse arguments."""
|
|
|
|
# used lambda to change args order and able to substitute width
|
|
|
|
fl = functools.partial(lambda w, t: textwrap.fill(t, w), 80)
|
2019-01-28 12:16:33 +01:00
|
|
|
description = [
|
2019-01-29 12:07:09 +01:00
|
|
|
"Hammer - Kea development environment management tool.\n",
|
2019-01-28 12:16:33 +01:00
|
|
|
fl("At first it is required to install Hammer dependencies which is Vagrant and either "
|
|
|
|
"VirtualBox or LXC. To make life easier Hammer can install Vagrant and required "
|
|
|
|
"Vagrant plugins using the command:"),
|
|
|
|
"\n ./hammer.py ensure-hammer-deps\n",
|
|
|
|
"Still VirtualBox and LXC need to be installed manually.",
|
|
|
|
fl("Basic functionality provided by Hammer is preparing building environment and "
|
|
|
|
"performing actual build and running unit tests locally, in current system. "
|
|
|
|
"This can be achieved by running the command:"),
|
|
|
|
"\n ./hammer.py build -p local\n",
|
|
|
|
fl("The scope of the process can be defined using --with (-w) and --without (-x) options. "
|
|
|
|
"By default the build command will build Kea with documentation, install it locally "
|
|
|
|
"and run unit tests."),
|
|
|
|
"To exclude installation and generating docs do:",
|
|
|
|
"\n ./hammer.py build -p local -x install docs\n",
|
|
|
|
fl("The whole list of available features is: %s." % ", ".join(ALL_FEATURES)),
|
|
|
|
fl("Hammer can be told to set up a new virtual machine with specified operating system "
|
|
|
|
"and not running the build:"),
|
|
|
|
"\n ./hammer.py prepare-system -p virtualbox -s freebsd -r 12.0\n",
|
|
|
|
fl("This way we can prepare a system for our own use. To get to such system using SSH invoke:"),
|
|
|
|
"\n ./hammer.py ssh -p virtualbox -s freebsd -r 12.0\n",
|
|
|
|
"To list all created system on a host invoke:",
|
|
|
|
"\n ./hammer.py created-systems\n",
|
|
|
|
"And then to destroy a given system run:",
|
|
|
|
"\n ./hammer.py destroy -d /path/to/dir/with/Vagrantfile\n",
|
|
|
|
]
|
|
|
|
description = "\n".join(description)
|
|
|
|
main_parser = argparse.ArgumentParser(description=description,
|
|
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
|
|
|
2019-01-25 16:08:12 +01:00
|
|
|
main_parser.add_argument('-v', '--verbose', action='store_true', help='Enable verbose mode.')
|
|
|
|
main_parser.add_argument('-q', '--quiet', action='store_true', help='Enable quiet mode.')
|
|
|
|
|
|
|
|
subparsers = main_parser.add_subparsers(dest='command',
|
|
|
|
title="Hammer commands",
|
2019-01-28 12:16:33 +01:00
|
|
|
description=fl("The following commands are provided by Hammer. "
|
2019-01-31 11:36:38 +01:00
|
|
|
"To get more information about particular command invoke: "
|
|
|
|
"./hammer.py <command> -h."))
|
2019-01-25 16:08:12 +01:00
|
|
|
|
|
|
|
parent_parser1 = argparse.ArgumentParser(add_help=False)
|
2019-01-31 11:36:38 +01:00
|
|
|
parent_parser1.add_argument('-p', '--provider', default='virtualbox',
|
|
|
|
choices=['lxc', 'virtualbox', 'local', 'all'],
|
|
|
|
help="Backend build executor. If 'all' then build is executed several times "
|
|
|
|
"on all providers. If 'local' then build is executed on current system. "
|
|
|
|
"Default is 'virtualbox'.")
|
2019-01-25 16:08:12 +01:00
|
|
|
parent_parser1.add_argument('-s', '--system', default='all', choices=list(SYSTEMS.keys()) + ['all'],
|
2019-01-31 11:36:38 +01:00
|
|
|
help="Build is executed on selected system. If 'all' then build is executed "
|
|
|
|
"several times on all systems. If provider is 'local' then this option is ignored. "
|
|
|
|
"Default is 'all'.")
|
2019-01-25 16:08:12 +01:00
|
|
|
parent_parser1.add_argument('-r', '--revision', default='all',
|
|
|
|
help="Revision of selected system. If 'all' then build is executed several times "
|
2019-01-31 11:36:38 +01:00
|
|
|
"on all revisions of selected system. To list supported systems and their revisions "
|
|
|
|
"invoke 'supported-systems'. Default is 'all'.")
|
2019-01-25 16:08:12 +01:00
|
|
|
|
|
|
|
parent_parser2 = argparse.ArgumentParser(add_help=False)
|
2019-01-29 12:07:09 +01:00
|
|
|
hlp = "Enable features. Separate them by space or comma. List of available features: %s. Default is '%s'."
|
|
|
|
hlp = hlp % (", ".join(ALL_FEATURES), ' '.join(DEFAULT_FEATURES))
|
2019-01-31 11:36:38 +01:00
|
|
|
parent_parser2.add_argument('-w', '--with', metavar='FEATURE', nargs='+', default=set(),
|
|
|
|
action=CollectCommaSeparatedArgsAction, help=hlp)
|
|
|
|
hlp = "Disable features. Separate them by space or comma. List of available features: %s. Default is ''."
|
|
|
|
hlp = hlp % ", ".join(ALL_FEATURES)
|
|
|
|
parent_parser2.add_argument('-x', '--without', metavar='FEATURE', nargs='+', default=set(),
|
|
|
|
action=CollectCommaSeparatedArgsAction, help=hlp)
|
2022-09-05 19:19:09 +03:00
|
|
|
parent_parser2.add_argument('--with-randomly', metavar='FEATURE', nargs='+', default=set(),
|
|
|
|
action=CollectCommaSeparatedArgsAction, help=hlp)
|
2022-10-07 15:27:08 +03:00
|
|
|
parent_parser2.add_argument('--ignore-errors-for', metavar='FEATURE', nargs='+', default=set(),
|
|
|
|
action=CollectCommaSeparatedArgsAction, help=hlp)
|
2019-01-25 16:08:12 +01:00
|
|
|
parent_parser2.add_argument('-l', '--leave-system', action='store_true',
|
2019-01-31 11:36:38 +01:00
|
|
|
help='At the end of the command do not destroy vagrant system. Default behavior is '
|
2021-03-18 10:22:04 +02:00
|
|
|
'destroying the system.')
|
2019-01-31 11:36:38 +01:00
|
|
|
parent_parser2.add_argument('-c', '--clean-start', action='store_true',
|
|
|
|
help='If there is pre-existing system then it is destroyed first.')
|
|
|
|
parent_parser2.add_argument('-i', '--check-times', action='store_true',
|
2021-03-18 10:22:04 +02:00
|
|
|
help='Do not allow executing commands infinitely.')
|
2019-01-25 16:08:12 +01:00
|
|
|
parent_parser2.add_argument('-n', '--dry-run', action='store_true', help='Print only what would be done.')
|
|
|
|
|
|
|
|
|
2019-01-31 11:36:38 +01:00
|
|
|
parser = subparsers.add_parser('ensure-hammer-deps',
|
|
|
|
help="Install Hammer dependencies on current, host system.")
|
|
|
|
parser = subparsers.add_parser('supported-systems',
|
|
|
|
help="List system supported by Hammer for doing Kea development.")
|
2019-01-25 16:08:12 +01:00
|
|
|
parser = subparsers.add_parser('build', help="Prepare system and run Kea build in indicated system.",
|
|
|
|
parents=[parent_parser1, parent_parser2])
|
2019-01-31 11:36:38 +01:00
|
|
|
parser.add_argument('-j', '--jobs', default=0,
|
|
|
|
help='Number of processes used in compilation. Override make -j default value.')
|
2019-01-28 12:16:33 +01:00
|
|
|
parser.add_argument('-t', '--from-tarball', metavar='TARBALL_PATH',
|
2019-01-31 11:36:38 +01:00
|
|
|
help='Instead of building sources in current folder use provided tarball '
|
|
|
|
'package (e.g. tar.gz).')
|
2019-03-14 16:37:12 +01:00
|
|
|
parser.add_argument('--ccache-dir', default=None,
|
|
|
|
help='Path to CCache directory on host system.')
|
2019-04-10 10:50:15 +02:00
|
|
|
parser.add_argument('--pkg-version', default='0.0.1',
|
|
|
|
help='Kea version.')
|
|
|
|
parser.add_argument('--pkg-isc-version', default='isc0',
|
|
|
|
help='ISC build version of Kea.')
|
|
|
|
parser.add_argument('--upload', action='store_true',
|
|
|
|
help='Request uploading native packages to repository indicated by --repository-url.')
|
|
|
|
parser.add_argument('--repository-url', default=None,
|
|
|
|
help='Repository for 3rd party dependencies and for uploading built packages.')
|
2019-01-25 16:08:12 +01:00
|
|
|
parser = subparsers.add_parser('prepare-system',
|
2019-01-31 11:36:38 +01:00
|
|
|
help="Prepare system for doing Kea development i.e. install all required "
|
|
|
|
"dependencies and pre-configure the system. build command always first calls "
|
|
|
|
"prepare-system internally.",
|
2019-01-25 16:08:12 +01:00
|
|
|
parents=[parent_parser1, parent_parser2])
|
2019-03-14 16:37:12 +01:00
|
|
|
parser.add_argument('--ccache-dir', default=None,
|
|
|
|
help='Path to CCache directory on host system.')
|
2019-04-10 10:50:15 +02:00
|
|
|
parser.add_argument('--repository-url', default=None,
|
|
|
|
help='Repository for 3rd party dependencies and for uploading built packages.')
|
2019-01-25 16:08:12 +01:00
|
|
|
parser = subparsers.add_parser('ssh', help="SSH to indicated system.",
|
|
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
2019-01-31 11:36:38 +01:00
|
|
|
description="Allows getting into the system using SSH. If the system is "
|
|
|
|
"not present then it will be created first but not prepared. The command "
|
|
|
|
"can be run in 2 way: \n"
|
|
|
|
"1) ./hammer.py ssh -p <provider> -s <system> -r <revision>\n"
|
|
|
|
"2) ./hammer.py ssh -d <path-to-vagrant-dir>",
|
2019-01-25 16:08:12 +01:00
|
|
|
parents=[parent_parser1])
|
|
|
|
parser.add_argument('-d', '--directory', help='Path to directory with Vagrantfile.')
|
|
|
|
parser = subparsers.add_parser('created-systems', help="List ALL systems created by Hammer.")
|
|
|
|
parser = subparsers.add_parser('destroy', help="Destroy indicated system.",
|
|
|
|
description="Destroys system indicated by a path to directory with Vagrantfile. "
|
|
|
|
"To get the list of created systems run: ./hammer.py created-systems.")
|
|
|
|
parser.add_argument('-d', '--directory', help='Path to directory with Vagrantfile.')
|
2019-01-29 12:07:09 +01:00
|
|
|
parser = subparsers.add_parser('package-box',
|
2019-05-10 16:07:23 +02:00
|
|
|
help="Prepare system from scratch and package it into Vagrant Box. Prepared box can be "
|
2019-01-31 11:36:38 +01:00
|
|
|
"later deployed to Vagrant Cloud.",
|
2019-01-25 16:08:12 +01:00
|
|
|
parents=[parent_parser1, parent_parser2])
|
2019-04-10 10:50:15 +02:00
|
|
|
parser.add_argument('--repository-url', default=None,
|
|
|
|
help='Repository for 3rd party dependencies and for uploading built packages.')
|
2019-05-14 08:11:34 +02:00
|
|
|
parser.add_argument('-u', '--reuse', action='store_true',
|
2021-03-18 10:22:04 +02:00
|
|
|
help='Reuse existing system image, otherwise (default case) if there is any existing then destroy it first.')
|
2021-03-15 09:54:46 +01:00
|
|
|
parser.add_argument('-k', '--skip-upload', action='store_true',
|
|
|
|
help='Skip uploading prepared box to cloud, otherwise (default case) upload it.')
|
|
|
|
|
2019-01-25 16:08:12 +01:00
|
|
|
|
|
|
|
args = main_parser.parse_args()
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-01-31 14:51:58 +01:00
|
|
|
return args, main_parser
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
|
2019-01-25 16:08:12 +01:00
|
|
|
def list_supported_systems():
|
2019-01-31 11:36:38 +01:00
|
|
|
"""List systems hammer can support (with supported providers)."""
|
2018-12-27 15:15:08 +01:00
|
|
|
for system, revisions in SYSTEMS.items():
|
|
|
|
print('%s:' % system)
|
|
|
|
for r in revisions:
|
|
|
|
providers = []
|
|
|
|
for p in ['lxc', 'virtualbox']:
|
|
|
|
k = '%s-%s-%s' % (system, r, p)
|
|
|
|
if k in IMAGE_TEMPLATES:
|
|
|
|
providers.append(p)
|
|
|
|
providers = ', '.join(providers)
|
|
|
|
print(' - %s: %s' % (r, providers))
|
|
|
|
|
|
|
|
|
2019-01-25 16:08:12 +01:00
|
|
|
def list_created_systems():
|
2019-01-31 11:36:38 +01:00
|
|
|
"""List VMs that are created on this host by Hammer."""
|
2019-04-10 10:50:15 +02:00
|
|
|
_, output = execute('vagrant global-status --prune', quiet=True, capture=True)
|
2019-01-25 16:08:12 +01:00
|
|
|
systems = []
|
|
|
|
for line in output.splitlines():
|
|
|
|
if 'hammer' not in line:
|
|
|
|
continue
|
|
|
|
elems = line.split()
|
|
|
|
state = elems[3]
|
|
|
|
path = elems[4]
|
|
|
|
systems.append([path, state])
|
|
|
|
|
|
|
|
print('')
|
|
|
|
print('%-10s %s' % ('State', 'Path'))
|
|
|
|
print('-' * 80)
|
|
|
|
for path, state, in sorted(systems):
|
|
|
|
print('%-10s %s' % (state, path))
|
|
|
|
print('-' * 80)
|
|
|
|
print('To destroy a system run: ./hammer.py destroy -d <path>')
|
|
|
|
print('')
|
|
|
|
|
|
|
|
|
|
|
|
def destroy_system(path):
|
2020-09-23 13:45:18 +02:00
|
|
|
"""Destroy Vagrant system under given path."""
|
2021-01-05 10:12:00 +01:00
|
|
|
vf = os.path.join(path, 'Vagrantfile')
|
|
|
|
if not os.path.exists(vf):
|
|
|
|
print('Wrong directory. It does not have Vagrantfile.')
|
|
|
|
sys.exit(1)
|
2019-01-25 16:08:12 +01:00
|
|
|
execute('vagrant destroy', cwd=path, interactive=True)
|
|
|
|
|
|
|
|
|
2022-09-05 19:19:09 +03:00
|
|
|
def _coin_toss():
|
|
|
|
if random.randint(0, 65535) % 2 == 0:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
2019-01-31 11:36:38 +01:00
|
|
|
def _get_features(args):
|
2018-12-27 15:15:08 +01:00
|
|
|
features = set(vars(args)['with'])
|
2019-12-20 09:58:04 +01:00
|
|
|
|
|
|
|
# establish initial set of features
|
|
|
|
if 'all' in features:
|
2022-09-05 22:28:01 +03:00
|
|
|
# special case 'all' but some features need to be removed
|
2019-12-20 09:58:04 +01:00
|
|
|
# as they are not compatible with others
|
|
|
|
features = set(ALL_FEATURES)
|
|
|
|
features.discard('all')
|
2023-07-18 11:56:44 +00:00
|
|
|
# do not include `native-pkg` in `all` if not set explicitly in parameters
|
2023-07-06 08:04:07 +00:00
|
|
|
if 'native-pkg' not in set(vars(args)['with']):
|
|
|
|
features.discard('native-pkg')
|
2019-12-20 09:58:04 +01:00
|
|
|
|
|
|
|
# if we build native packages then some features are required and some not
|
2019-04-10 10:50:15 +02:00
|
|
|
if 'native-pkg' in features:
|
|
|
|
features.add('docs')
|
|
|
|
features.add('perfdhcp')
|
|
|
|
features.add('shell')
|
|
|
|
features.add('mysql')
|
|
|
|
features.add('pgsql')
|
|
|
|
features.add('radius')
|
2021-06-28 12:19:36 +02:00
|
|
|
features.add('gssapi')
|
2021-06-07 14:52:51 +02:00
|
|
|
# in case of build command of native packages, unittest should not
|
|
|
|
# be run as they are not built
|
|
|
|
if args.command == 'build':
|
|
|
|
features.discard('unittest')
|
2019-12-20 09:58:04 +01:00
|
|
|
|
2022-09-05 19:19:09 +03:00
|
|
|
nofeatures = set(args.without)
|
|
|
|
features = features.difference(nofeatures)
|
|
|
|
|
|
|
|
for i in args.with_randomly:
|
|
|
|
if _coin_toss():
|
|
|
|
features.add(i)
|
|
|
|
log.info(f'Feature enabled through coin toss: {i}')
|
|
|
|
else:
|
|
|
|
features.discard(i)
|
|
|
|
log.info(f'Feature disabled through coin toss: {i}')
|
|
|
|
|
|
|
|
if hasattr(args, 'ccache_dir') and args.ccache_dir:
|
|
|
|
features.add('ccache')
|
|
|
|
|
2022-10-03 11:16:38 +03:00
|
|
|
return features
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
|
2019-01-10 17:36:02 +01:00
|
|
|
def _print_summary(results, features):
|
2021-03-18 10:22:04 +02:00
|
|
|
"""Print summary of build times and unit-test results."""
|
2018-12-27 15:15:08 +01:00
|
|
|
print("")
|
2019-01-10 17:36:02 +01:00
|
|
|
print("+===== Hammer Summary ====================================================+")
|
|
|
|
print("| provider | system | revision | duration | status | unit tests |")
|
|
|
|
print("+------------+------------+----------+-----------+---------+--------------+")
|
2018-12-27 15:15:08 +01:00
|
|
|
total_dt = 0
|
|
|
|
for key, result in results.items():
|
|
|
|
provider, system, revision = key
|
2019-01-10 17:36:02 +01:00
|
|
|
dt, error, ut_total, ut_passed = result
|
|
|
|
|
2018-12-27 15:15:08 +01:00
|
|
|
total_dt += dt
|
2019-01-10 17:36:02 +01:00
|
|
|
if error is None:
|
|
|
|
status = ' %s' % green('ok')
|
|
|
|
elif error == 'not run':
|
|
|
|
status = blue('not run')
|
|
|
|
else:
|
|
|
|
status = ' %s' % red('error')
|
|
|
|
|
|
|
|
if 'unittest' in features:
|
|
|
|
ut_results = '%s/%s' % (ut_passed, ut_total)
|
|
|
|
padding = ' ' * (12 - len(ut_results))
|
|
|
|
if ut_passed < ut_total or ut_total == 0:
|
|
|
|
ut_results = padding + red(ut_results)
|
|
|
|
else:
|
|
|
|
ut_results = padding + green(ut_results)
|
|
|
|
else:
|
|
|
|
ut_results = ' not planned'
|
2019-01-31 11:36:38 +01:00
|
|
|
txt = '| %10s | %10s | %8s | %6d:%02d | %s | %s |' % (provider, system, revision,
|
|
|
|
dt // 60, dt % 60, status, ut_results)
|
|
|
|
print(txt)
|
2019-01-10 17:36:02 +01:00
|
|
|
print("+------------+------------+----------+-----------+---------+--------------+")
|
2019-01-31 11:36:38 +01:00
|
|
|
txt = "| Total: %6d:%02d | |" % (total_dt // 60,
|
|
|
|
total_dt % 60)
|
|
|
|
print(txt)
|
2019-01-10 17:36:02 +01:00
|
|
|
print("+=========================================================================+")
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
|
2019-01-28 17:32:26 +01:00
|
|
|
def _check_system_revision(system, revision):
|
2019-01-29 11:30:05 +01:00
|
|
|
if revision == 'all':
|
|
|
|
return
|
2019-01-28 17:32:26 +01:00
|
|
|
revs = SYSTEMS[system]
|
|
|
|
if revision not in revs:
|
|
|
|
msg = "hammer.py error: argument -r/--revision: invalid choice: '%s' (choose from '%s')"
|
|
|
|
msg = msg % (revision, "', '".join(revs))
|
|
|
|
print(msg)
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
2019-03-14 16:37:12 +01:00
|
|
|
def _prepare_ccache_dir(ccache_dir, system, revision):
|
|
|
|
if not ccache_dir:
|
|
|
|
return None
|
|
|
|
|
|
|
|
ccache_dir = os.path.join(ccache_dir, "%s-%s" % (system, revision))
|
|
|
|
ccache_dir = os.path.abspath(ccache_dir)
|
|
|
|
if not os.path.exists(ccache_dir):
|
|
|
|
os.makedirs(ccache_dir)
|
|
|
|
return ccache_dir
|
|
|
|
|
|
|
|
|
2019-01-29 12:07:09 +01:00
|
|
|
def prepare_system_cmd(args):
|
2019-01-31 11:36:38 +01:00
|
|
|
"""Check command args and run the prepare-system command."""
|
2019-01-29 12:07:09 +01:00
|
|
|
if args.provider != 'local' and (args.system == 'all' or args.revision == 'all'):
|
|
|
|
print('Please provide required system and its version.')
|
|
|
|
print('Example: ./hammer.py prepare-system -s fedora -r 28.')
|
|
|
|
print('To get list of supported systems run: ./hammer.py supported-systems.')
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
_check_system_revision(args.system, args.revision)
|
|
|
|
|
2019-01-31 11:36:38 +01:00
|
|
|
features = _get_features(args)
|
2019-01-29 12:07:09 +01:00
|
|
|
log.info('Enabled features: %s', ' '.join(features))
|
|
|
|
|
|
|
|
if args.provider == 'local':
|
2022-10-07 15:27:08 +03:00
|
|
|
prepare_system_local(features, args.check_times, args.ignore_errors_for)
|
2019-01-29 12:07:09 +01:00
|
|
|
return
|
|
|
|
|
2019-03-14 16:37:12 +01:00
|
|
|
ccache_dir = _prepare_ccache_dir(args.ccache_dir, args.system, args.revision)
|
|
|
|
|
2021-01-05 10:12:00 +01:00
|
|
|
_check_deps_presence()
|
2019-01-31 11:36:38 +01:00
|
|
|
prepare_system_in_vagrant(args.provider, args.system, args.revision, features,
|
2019-03-14 16:37:12 +01:00
|
|
|
args.dry_run, args.check_times, args.clean_start,
|
|
|
|
ccache_dir)
|
2019-01-29 12:07:09 +01:00
|
|
|
|
2021-08-27 18:54:59 +03:00
|
|
|
|
2021-02-16 11:50:25 +01:00
|
|
|
def upload_to_repo(args, pkgs_dir):
|
2021-08-27 18:54:59 +03:00
|
|
|
# NOTE: note the differences (if any) in system/revision vs args.system/revision
|
|
|
|
system, revision = get_system_revision()
|
|
|
|
repo_url = _get_full_repo_url(args.repository_url, system, revision, args.pkg_version)
|
|
|
|
assert repo_url is not None
|
|
|
|
upload_cmd = 'curl -v --netrc -f'
|
|
|
|
log.info('args.system %s, system = %s', args.system, system)
|
|
|
|
|
|
|
|
file_ext = ''
|
|
|
|
if system in ['ubuntu', 'debian']:
|
|
|
|
upload_cmd += ' -X POST -H "Content-Type: multipart/form-data" --data-binary "@%s" '
|
2023-03-29 11:01:10 +00:00
|
|
|
file_ext = 'deb' # include both '.deb' and '.ddeb' files
|
2021-08-27 18:54:59 +03:00
|
|
|
|
|
|
|
elif system in ['fedora', 'centos', 'rhel']:
|
|
|
|
upload_cmd += ' --upload-file %s '
|
|
|
|
file_ext = '.rpm'
|
|
|
|
|
|
|
|
elif system == 'alpine':
|
|
|
|
upload_cmd += ' --upload-file %s '
|
|
|
|
file_ext = ''
|
|
|
|
repo_url = urljoin(repo_url, '%s/v%s/x86_64/' % (args.pkg_isc_version, revision))
|
|
|
|
|
|
|
|
upload_cmd += ' ' + repo_url
|
|
|
|
|
|
|
|
for fn in os.listdir(pkgs_dir):
|
|
|
|
log.info("debug: fn = %s", fn)
|
|
|
|
if file_ext and not fn.endswith(file_ext):
|
|
|
|
log.info('File extension "%s" is not supported by upload_to_repo function', file_ext)
|
|
|
|
continue
|
|
|
|
fp = os.path.join(pkgs_dir, fn)
|
|
|
|
log.info("upload cmd: %s", upload_cmd)
|
|
|
|
log.info("fp: %s", fp)
|
|
|
|
cmd = upload_cmd % fp
|
2021-09-02 15:02:08 +03:00
|
|
|
|
|
|
|
attempts=4
|
|
|
|
while attempts > 0:
|
|
|
|
exitcode, output = execute(cmd, capture=True)
|
|
|
|
if exitcode != 0 and '504 Gateway Time-out' in output:
|
|
|
|
log.info('Trying again after 8 seconds...')
|
|
|
|
attempts -= 1
|
|
|
|
time.sleep(8)
|
|
|
|
else:
|
|
|
|
break
|
2021-08-27 18:54:59 +03:00
|
|
|
|
2019-01-29 12:07:09 +01:00
|
|
|
|
|
|
|
def build_cmd(args):
|
2019-01-31 11:36:38 +01:00
|
|
|
"""Check command args and run the build command."""
|
|
|
|
features = _get_features(args)
|
2019-01-29 12:07:09 +01:00
|
|
|
log.info('Enabled features: %s', ' '.join(features))
|
|
|
|
if args.provider == 'local':
|
2021-02-16 11:50:25 +01:00
|
|
|
# NOTE: working dir is /tmp/workspace/kea-dev/pkg
|
|
|
|
pkgs_dir = "kea-pkg"
|
|
|
|
if os.path.exists(pkgs_dir):
|
|
|
|
execute('rm -rf %s' % pkgs_dir)
|
|
|
|
os.makedirs(pkgs_dir)
|
|
|
|
|
2019-03-14 16:37:12 +01:00
|
|
|
build_local(features, args.from_tarball, args.check_times, int(args.jobs), args.dry_run,
|
2021-02-16 11:50:25 +01:00
|
|
|
args.ccache_dir, args.pkg_version, args.pkg_isc_version, args.repository_url, pkgs_dir)
|
|
|
|
# NOTE: upload the locally build packages and leave; the rest of the code is vagrant specific
|
|
|
|
if args.upload:
|
|
|
|
upload_to_repo(args,pkgs_dir)
|
|
|
|
|
2019-01-29 12:07:09 +01:00
|
|
|
return
|
|
|
|
|
|
|
|
_check_system_revision(args.system, args.revision)
|
|
|
|
|
2019-05-15 17:15:43 +02:00
|
|
|
if 'native-pkg' in features and not args.repository_url:
|
|
|
|
msg = "Enabling 'native-pkg' requires passing --repository-url."
|
|
|
|
print(msg)
|
|
|
|
sys.exit(1)
|
|
|
|
|
2021-01-05 10:12:00 +01:00
|
|
|
_check_deps_presence()
|
|
|
|
|
2019-01-29 12:07:09 +01:00
|
|
|
if args.provider == 'all':
|
|
|
|
providers = ['lxc', 'virtualbox']
|
|
|
|
else:
|
|
|
|
providers = [args.provider]
|
|
|
|
|
|
|
|
if args.system == 'all':
|
|
|
|
systems = SYSTEMS.keys()
|
|
|
|
else:
|
|
|
|
systems = [args.system]
|
|
|
|
|
|
|
|
plan = []
|
|
|
|
results = {}
|
|
|
|
log.info('Build plan:')
|
|
|
|
for provider in providers:
|
|
|
|
for system in systems:
|
|
|
|
if args.revision == 'all':
|
|
|
|
revisions = SYSTEMS[system]
|
|
|
|
else:
|
|
|
|
revisions = [args.revision]
|
|
|
|
|
|
|
|
for revision in revisions:
|
|
|
|
if args.revision == 'all':
|
|
|
|
key = '%s-%s-%s' % (system, revision, provider)
|
|
|
|
if key not in IMAGE_TEMPLATES:
|
|
|
|
continue
|
|
|
|
plan.append((provider, system, revision))
|
|
|
|
log.info(' - %s, %s, %s', provider, system, revision)
|
|
|
|
results[(provider, system, revision)] = (0, 'not run')
|
|
|
|
|
|
|
|
fail = False
|
|
|
|
for provider, system, revision in plan:
|
2019-03-14 16:37:12 +01:00
|
|
|
ccache_dir = _prepare_ccache_dir(args.ccache_dir, args.system, args.revision)
|
2019-01-29 12:07:09 +01:00
|
|
|
result = build_in_vagrant(provider, system, revision, features, args.leave_system, args.from_tarball,
|
2019-03-14 16:37:12 +01:00
|
|
|
args.dry_run, args.quiet, args.clean_start, args.check_times, int(args.jobs),
|
2019-04-10 10:50:15 +02:00
|
|
|
ccache_dir, args.pkg_version, args.pkg_isc_version, args.upload, args.repository_url)
|
2019-01-29 12:07:09 +01:00
|
|
|
results[(provider, system, revision)] = result
|
|
|
|
|
|
|
|
error = result[1]
|
|
|
|
if error:
|
|
|
|
fail = True
|
|
|
|
if isinstance(error, KeyboardInterrupt):
|
|
|
|
break
|
|
|
|
|
|
|
|
_print_summary(results, features)
|
|
|
|
|
|
|
|
if fail:
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
2021-01-05 10:12:00 +01:00
|
|
|
def _check_deps_presence():
|
2021-01-05 15:37:38 +01:00
|
|
|
ret = execute('vagrant -v', super_quiet=True, raise_error=False)
|
|
|
|
if ret != 0:
|
|
|
|
print('Missing vagrant. Please install it from https://www.vagrantup.com/')
|
2021-01-05 10:12:00 +01:00
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
2018-12-27 15:15:08 +01:00
|
|
|
def main():
|
2019-01-31 11:36:38 +01:00
|
|
|
"""Main function - parse args and invoke proper command."""
|
2019-01-31 14:51:58 +01:00
|
|
|
args, parser = parse_args()
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-01-29 12:07:09 +01:00
|
|
|
# prepare logging
|
2018-12-27 15:15:08 +01:00
|
|
|
if args.verbose:
|
|
|
|
level = logging.DEBUG
|
2019-04-10 10:50:15 +02:00
|
|
|
fmt = '[HAMMER] %(asctime)-15s L%(lineno)04d %(message)s'
|
|
|
|
else:
|
|
|
|
level = logging.INFO
|
|
|
|
fmt = '[HAMMER] %(asctime)-15s %(message)s'
|
2019-01-29 12:07:09 +01:00
|
|
|
logging.basicConfig(format=fmt, level=level)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-01-29 12:07:09 +01:00
|
|
|
# dispatch command
|
2019-01-25 16:08:12 +01:00
|
|
|
if args.command == 'supported-systems':
|
|
|
|
list_supported_systems()
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-01-25 16:08:12 +01:00
|
|
|
elif args.command == 'created-systems':
|
2021-01-05 10:12:00 +01:00
|
|
|
_check_deps_presence()
|
2019-01-25 16:08:12 +01:00
|
|
|
list_created_systems()
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
elif args.command == "package-box":
|
2021-01-05 10:12:00 +01:00
|
|
|
_check_deps_presence()
|
2019-01-28 17:32:26 +01:00
|
|
|
_check_system_revision(args.system, args.revision)
|
2021-06-28 12:19:36 +02:00
|
|
|
features = set(['docs', 'perfdhcp', 'shell', 'mysql', 'pgsql', 'radius', 'gssapi', 'native-pkg'])
|
2020-03-19 12:48:18 +01:00
|
|
|
|
2018-12-27 15:15:08 +01:00
|
|
|
log.info('Enabled features: %s', ' '.join(features))
|
2021-03-15 09:54:46 +01:00
|
|
|
package_box(args.provider, args.system, args.revision, features, args.dry_run, args.check_times, args.reuse, args.skip_upload)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
elif args.command == "prepare-system":
|
2019-01-29 12:07:09 +01:00
|
|
|
prepare_system_cmd(args)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
elif args.command == "build":
|
2019-01-29 12:07:09 +01:00
|
|
|
build_cmd(args)
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
elif args.command == "ssh":
|
2019-01-28 17:32:26 +01:00
|
|
|
_check_system_revision(args.system, args.revision)
|
2021-01-05 10:12:00 +01:00
|
|
|
if not args.system or not args.revision or args.system == 'all' or args.revision == 'all':
|
|
|
|
print('System (-s) and revision (-r) parameters are required')
|
|
|
|
sys.exit(1)
|
|
|
|
_check_deps_presence()
|
2019-01-25 16:08:12 +01:00
|
|
|
ssh(args.provider, args.system, args.revision)
|
2019-01-10 17:36:02 +01:00
|
|
|
|
|
|
|
elif args.command == "ensure-hammer-deps":
|
|
|
|
ensure_hammer_deps()
|
2018-12-27 15:15:08 +01:00
|
|
|
|
2019-01-25 16:08:12 +01:00
|
|
|
elif args.command == "destroy":
|
2021-01-05 10:12:00 +01:00
|
|
|
if not args.directory:
|
|
|
|
print('Missing directory (-d) parameter')
|
|
|
|
sys.exit(1)
|
|
|
|
_check_deps_presence()
|
2019-01-25 16:08:12 +01:00
|
|
|
destroy_system(args.directory)
|
|
|
|
|
2019-01-31 14:51:58 +01:00
|
|
|
else:
|
|
|
|
parser.print_help()
|
|
|
|
|
2018-12-27 15:15:08 +01:00
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|