# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import itertools import os from oslo_config import cfg from oslo_config import types from kolla.common.sources import SOURCES from kolla.common.users import USERS from kolla.version import version_info as version BASE_OS_DISTRO = ['centos', 'debian', 'rocky', 'ubuntu'] BASE_ARCH = ['x86_64', 'aarch64'] DEFAULT_BASE_TAGS = { 'centos': {'name': 'quay.io/centos/centos', 'tag': 'stream9'}, 'debian': {'name': 'debian', 'tag': 'bookworm'}, 'rocky': {'name': 'quay.io/rockylinux/rockylinux', 'tag': '9'}, 'ubuntu': {'name': 'ubuntu', 'tag': '22.04'}, } # NOTE(hrw): has to match PRETTY_NAME in /etc/os-release DISTRO_PRETTY_NAME = { 'centos': 'CentOS Stream 9', 'debian': 'Debian GNU/Linux 12 (bookworm)', 'rocky': 'Rocky Linux 9.* (Blue Onyx)', 'ubuntu': 'Ubuntu 22.04', } OPENSTACK_RELEASE = 'master' # This is noarch repository so we will use it on all architectures DELOREAN_DEPS = "https://trunk.rdoproject.org/centos9-master/" \ "delorean-deps.repo" # TODO(mandre) check for file integrity instead of downloading from an HTTPS # source TARBALLS_BASE = "https://tarballs.opendev.org" _PROFILE_OPTS = [ cfg.ListOpt('infra', default=[ 'cron', 'etcd', 'fluentd', 'haproxy', 'hacluster', 'keepalived', 'kolla-toolbox', 'letsencrypt', 'mariadb', 'memcached', 'opensearch', 'openvswitch', 'proxysql', 'rabbitmq', 'redis', 'storm', 'tgtd', ], help='Infra images'), cfg.ListOpt('main', default=[ 'ceilometer', 'cinder', 'glance', 'heat', 'horizon', 'iscsi', 'keystone', 'neutron', 'nova-', 'placement', 'swift', ], help='Main images'), cfg.ListOpt('aux', default=[ 'aodh', 'blazar', 'cloudkitty', 'designate', 'freezer', 'gnocchi', 'influxdb', 'ironic', 'kafka', 'kuryr', 'magnum', 'manila', 'masakari', 'mistral', 'murano', 'octavia', 'redis', 'sahara', 'senlin', 'solum', 'tacker', 'telegraf', 'trove', 'vitrage', 'zookeeper', 'zun', ], help='Aux Images'), cfg.ListOpt('default', default=[ 'cron', 'kolla-toolbox', 'fluentd', 'glance', 'haproxy', 'heat', 'horizon', 'keepalived', 'keystone', 'mariadb', 'memcached', 'neutron', 'nova-', 'placement', 'proxysql', 'openvswitch', 'rabbitmq', ], help='Default images'), ] hostarch = os.uname()[4] if hostarch == 'aarch64': debianarch = 'arm64' elif hostarch == 'x86_64': debianarch = 'amd64' _CLI_OPTS = [ cfg.StrOpt('base', short='b', default='rocky', choices=BASE_OS_DISTRO, help='The distro type of the base image.'), cfg.StrOpt('base-tag', default='latest', help='The base distro image tag'), cfg.StrOpt('base-image', help='The base image name. Default is the same with base.'), cfg.StrOpt('base-arch', default=hostarch, choices=BASE_ARCH, help='The base architecture. Default is same as host.'), cfg.StrOpt('debian-arch', default=debianarch), cfg.BoolOpt('use-dumb-init', default=True, help='Use dumb-init as init system in containers'), cfg.BoolOpt('debug', short='d', default=False, help='Turn on debugging log level'), cfg.BoolOpt('skip-parents', default=False, help='Do not rebuild parents of matched images'), cfg.BoolOpt('skip-existing', default=False, help='Do not rebuild images present in the container engine ' 'cache'), cfg.DictOpt('build-args', help='Set docker build time variables'), cfg.BoolOpt('keep', default=False, help='Keep failed intermediate containers'), cfg.BoolOpt('list-dependencies', short='l', help='Show image dependencies (filtering supported)'), cfg.BoolOpt('list-images', help='Show all available images (filtering supported)'), cfg.StrOpt('locals-base', default='./', help='Base directory for local source resolution'), cfg.StrOpt('namespace', short='n', default='kolla', help='The Docker namespace name'), cfg.StrOpt('network_mode', default='host', help='The network mode for Docker build. Example: host'), cfg.BoolOpt('cache', default=True, help='Use the container engine cache when building'), cfg.MultiOpt('profile', types.String(), short='p', help=('Build a pre-defined set of images, see [profiles]' ' section in config. The default profiles are:' ' {}'.format(', '.join( [opt.name for opt in _PROFILE_OPTS]) ))), cfg.BoolOpt('push', default=False, help='Push images after building'), cfg.IntOpt('push-threads', default=1, min=1, help=('The number of threads to use while pushing images.' ' Note: Docker cannot handle threaded pushing properly')), cfg.IntOpt('retries', short='r', default=3, min=0, help='The number of times to retry while building'), cfg.MultiOpt('regex', types.String(), positional=True, required=False, help=('Build only images matching regex and its' ' dependencies')), cfg.StrOpt('registry', help=('The container image registry host. The default registry' ' host is Docker Hub')), cfg.StrOpt('save-dependency', help=('Path to the file to store the docker image' ' dependency in Graphviz dot format')), cfg.StrOpt('format', short='f', default='json', choices=['json', 'none'], help='Format to write the final results in.'), cfg.StrOpt('summary-json-file', help='Name of a file to write the build summary to when format ' 'is json. If unset, the summary will be written to ' 'standard output'), cfg.StrOpt('tarballs-base', default=TARBALLS_BASE, help='Base url to OpenStack tarballs'), cfg.IntOpt('threads', short='T', default=8, min=1, help=('The number of threads to use while building.' ' (Note: setting to one will allow real time' ' logging)')), cfg.StrOpt('tag', default=version.cached_version_string(), help='The container image tag'), cfg.BoolOpt('template-only', default=False, help="Don't build images. Generate Dockerfile only"), cfg.IntOpt('timeout', default=120, help='Time in seconds after which any operation times out'), cfg.MultiOpt('template-override', types.String(), help='Path to template override file'), cfg.MultiOpt('docker-dir', types.String(), help=('Path to additional docker file template directory,' ' can be specified multiple times'), short='D'), cfg.StrOpt('logs-dir', help='Path to logs directory'), cfg.BoolOpt('pull', default=True, help='Attempt to pull a newer version of the base image'), cfg.StrOpt('work-dir', help=('Path to be used as working directory.' ' By default, a temporary dir is created')), cfg.BoolOpt('squash', default=False, help=('Squash the image layers. WARNING: it will consume lots' ' of disk IO. "docker-squash" tool is required, install' ' it by "pip install docker-squash"')), cfg.StrOpt('openstack-release', default=OPENSTACK_RELEASE, help='OpenStack release for building kolla source images and ' 'kolla-toolbox image'), cfg.StrOpt('openstack-branch', help='Branch for source images (internal; with a dash; ' 'please set openstack-release instead)'), cfg.StrOpt('openstack-branch-slashed', help='Branch for source images (internal; with a slash; ' 'please set openstack-release instead)'), cfg.BoolOpt('docker-healthchecks', default=True, help='Add Kolla docker healthcheck scripts in the image'), cfg.BoolOpt('quiet', short='q', default=False, help='Do not print image logs'), cfg.BoolOpt('enable-unbuildable', default=False, help='Enable images marked as unbuildable'), cfg.BoolOpt('summary', default=True, help='Show summary at the end of build'), cfg.StrOpt('image-name-prefix', default='', help='Prefix prepended to image names'), cfg.StrOpt('repos-yaml', default='', help='Path to alternative repos.yaml file'), cfg.StrOpt('engine', default='docker', choices=['docker', 'podman'], help='Container engine to build images on.'), cfg.StrOpt('podman_base_url', default='unix:///run/podman/podman.sock', help='Path to podman socket.') ] _BASE_OPTS = [ cfg.StrOpt('maintainer', default='Kolla Project (https://launchpad.net/kolla)', help='Content of the maintainer label'), cfg.StrOpt('distro_package_manager', default=None, help=('Use this parameter to override the default package ' 'manager used by kolla. For example, if you want to use ' 'yum on a system with dnf, set this to yum which will ' 'use yum command in the build process')), cfg.StrOpt('base_package_type', default=None, help=('Set the package type of the distro. If not set then ' 'the packaging type is set to "rpm" if a RHEL based ' 'distro and "deb" if a Debian based distro.')), cfg.ListOpt('rpm_setup_config', default=[DELOREAN_DEPS], help=('Comma separated list of .rpm or .repo file(s) ' 'or URL(s) to install before building containers')), cfg.StrOpt('apt_sources_list', help=('Path to custom sources.list')), cfg.StrOpt('apt_preferences', help=('Path to custom apt/preferences')), cfg.BoolOpt('squash-cleanup', default=True, help='Remove source image from Docker after squashing'), cfg.StrOpt('squash-tmp-dir', help='Temporary directory to be used during squashing'), cfg.BoolOpt('clean_package_cache', default=True, help='Clean all package cache.'), cfg.ListOpt('allowed-to-fail', default=[], help='Images which are allowed to fail'), ] def get_source_opts(type_=None, location=None, reference=None, enabled=True, version=None, sha256=None): return [cfg.StrOpt('type', choices=['local', 'git', 'url'], default=type_, help='Source location type'), cfg.StrOpt('location', default=location, help='The location for source install'), cfg.StrOpt('reference', default=reference, help=('Git reference to pull, commit sha, tag ' 'or branch name')), cfg.BoolOpt('enabled', default=enabled, help=('Whether the source is enabled')), cfg.StrOpt('version', default=version, help=('Package version to download for GitHub ' 'sources')), cfg.DictOpt('sha256', default=sha256)] def get_user_opts(uid, gid, group): return [ cfg.IntOpt('uid', default=uid, help='The user id'), cfg.IntOpt('gid', default=gid, help='The group id'), cfg.StrOpt('group', default=group, help='The group name'), ] def gen_all_user_opts(): for name, params in USERS.items(): uid = params['uid'] gid = params['gid'] try: group = params['group'] except KeyError: group = name[:-5] yield name, get_user_opts(uid, gid, group) def gen_all_source_opts(): for name, params in SOURCES.items(): type_ = params['type'] location = params['location'] reference = params.get('reference') enabled = params.get('enabled', True) version = params.get('version') sha256 = params.get('sha256') yield name, get_source_opts(type_, location, reference, enabled, version, sha256) def list_opts(): return itertools.chain([(None, _CLI_OPTS), (None, _BASE_OPTS), ('profiles', _PROFILE_OPTS)], gen_all_source_opts(), gen_all_user_opts(), ) def parse(conf, args, usage=None, prog=None, default_config_files=None): conf.register_cli_opts(_CLI_OPTS) conf.register_opts(_BASE_OPTS) conf.register_opts(_PROFILE_OPTS, group='profiles') for name, opts in gen_all_source_opts(): conf.register_opts(opts, name) for name, opts in gen_all_user_opts(): conf.register_opts(opts, name) conf(args=args, project='kolla', usage=usage, prog=prog, version=version.cached_version_string(), default_config_files=default_config_files) # NOTE(jeffrey4l): set the default base tag based on the # base option conf.set_default('base_tag', DEFAULT_BASE_TAGS[conf.base]['tag']) prefix = '' if conf.openstack_release == 'master' else 'stable-' openstack_branch = '{}{}'.format(prefix, conf.openstack_release) openstack_branch_slashed = openstack_branch.replace('-', '/') conf.set_default('openstack_branch', openstack_branch) conf.set_default('openstack_branch_slashed', openstack_branch_slashed) if not conf.base_image: conf.base_image = DEFAULT_BASE_TAGS[conf.base]['name'] conf.debian_arch = 'amd64'