Add settings to fuel-bootstrap CLI
Change-Id: I2610333cf90827915786ee585fd9091c6ff9a17e Implements: blueprint bootstrap-images-support-in-cli
This commit is contained in:
parent
283624a1a6
commit
bd67efbada
|
@ -47,7 +47,7 @@ class BuildCommand(command.Command):
|
|||
)
|
||||
parser.add_argument(
|
||||
'--repo',
|
||||
dest='repos',
|
||||
dest='extra_repos',
|
||||
type=str,
|
||||
metavar='REPOSITORY',
|
||||
help="Add one more repository. format 'type uri"
|
||||
|
@ -169,4 +169,6 @@ class BuildCommand(command.Command):
|
|||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
bs_image.make_bootstrap(parsed_args)
|
||||
image_uuid, path = bs_image.make_bootstrap(parsed_args)
|
||||
self.app.stdout.write("Bootstrap image {0} has been built: {1}\n"
|
||||
.format(image_uuid, path))
|
||||
|
|
|
@ -36,5 +36,5 @@ class ImportCommand(command.Command):
|
|||
def take_action(self, parsed_args):
|
||||
# Cliff handles errors by himself
|
||||
image_uuid = bs_image.import_image(parsed_args.filename)
|
||||
self.app.stdout.write("Bootstrap image {0} has been imported"
|
||||
self.app.stdout.write("Bootstrap image {0} has been imported.\n"
|
||||
.format(image_uuid))
|
||||
|
|
|
@ -14,14 +14,12 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
|
||||
# FIXME: Move configurable consts to settings.yaml
|
||||
# These consts shouldn't be configured
|
||||
|
||||
BOOTSTRAP_IMAGES_DIR = "/var/www/nailgun/bootstraps/"
|
||||
# TODO(asvechnikov): add possibility to specify custom config file
|
||||
CONFIG_FILE = "/etc/fuel-agent/fuel_bootstrap_cli.yaml"
|
||||
METADATA_FILE = "metadata.yaml"
|
||||
SYMLINK = os.path.join(BOOTSTRAP_IMAGES_DIR, "active_bootstrap")
|
||||
ASTUTE_FILE = "/etc/fuel/astute.yaml"
|
||||
CONTAINER_FORMAT = "tar.gz"
|
||||
ROOTFS = {'name': 'rootfs',
|
||||
'mask': 'rootfs',
|
||||
|
@ -43,26 +41,3 @@ BOOTSTRAP_MODULES = [
|
|||
IMAGE_DATA = {'/': ROOTFS}
|
||||
|
||||
UBUNTU_RELEASE = 'trusty'
|
||||
|
||||
# Packages required for the master node to discover a bootstrap node
|
||||
# Hardcoded list used for disable user-factor : when user can accidentally
|
||||
# remove fuel-required packages, and create totally non-working bootstrap
|
||||
DEFAULT_PACKAGES = [
|
||||
"openssh-client",
|
||||
"openssh-server",
|
||||
"ntp",
|
||||
"mcollective",
|
||||
"nailgun-agent",
|
||||
"nailgun-mcagents",
|
||||
"network-checker",
|
||||
"fuel-agent"
|
||||
"ubuntu-minimal",
|
||||
"live-boot",
|
||||
"live-boot-initramfs-tools",
|
||||
"wget",
|
||||
"linux-firmware",
|
||||
"linux-firmware-nonfree",
|
||||
"xz-utils",
|
||||
"squashfs-tools",
|
||||
"msmtp-mta"
|
||||
]
|
||||
|
|
|
@ -43,3 +43,7 @@ class IncorrectRepository(FuelBootstrapException):
|
|||
|
||||
class IncorrectImage(FuelBootstrapException):
|
||||
"""Should be raised when image has incorrect format"""
|
||||
|
||||
|
||||
class ConfigFileNotExists(FuelBootstrapException):
|
||||
"""Should be raised when default config file is not found"""
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2015 Mirantis, Inc.
|
||||
#
|
||||
# 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 os
|
||||
import yaml
|
||||
|
||||
from fuel_bootstrap import consts
|
||||
from fuel_bootstrap import errors
|
||||
|
||||
|
||||
class Configuration(object):
|
||||
def __init__(self, config_file=None):
|
||||
if not config_file:
|
||||
config_file = consts.CONFIG_FILE
|
||||
if os.path.exists(config_file):
|
||||
with open(config_file) as f:
|
||||
data = yaml.load(f)
|
||||
else:
|
||||
raise errors.ConfigFileNotExists(
|
||||
"Default config couldn't be found in {0}"
|
||||
.format(config_file))
|
||||
self._data = data
|
||||
|
||||
def __getattr__(self, name):
|
||||
return self._data.get(name)
|
|
@ -25,18 +25,19 @@ from fuel_agent.utils import utils
|
|||
|
||||
from fuel_bootstrap import consts
|
||||
from fuel_bootstrap import errors
|
||||
from fuel_bootstrap import settings
|
||||
from fuel_bootstrap.utils import data as data_util
|
||||
|
||||
|
||||
CONF = settings.Configuration()
|
||||
LOG = logging.getLogger(__name__)
|
||||
ACTIVE = 'active'
|
||||
|
||||
|
||||
def get_all():
|
||||
data = []
|
||||
LOG.debug("Searching images in %s", consts.BOOTSTRAP_IMAGES_DIR)
|
||||
for name in os.listdir(consts.BOOTSTRAP_IMAGES_DIR):
|
||||
if not os.path.isdir(os.path.join(consts.BOOTSTRAP_IMAGES_DIR, name)):
|
||||
LOG.debug("Searching images in %s", CONF.bootstrap_images_dir)
|
||||
for name in os.listdir(CONF.bootstrap_images_dir):
|
||||
if not os.path.isdir(os.path.join(CONF.bootstrap_images_dir, name)):
|
||||
continue
|
||||
try:
|
||||
data.append(parse(name))
|
||||
|
@ -85,12 +86,13 @@ def delete(image_id):
|
|||
|
||||
|
||||
def is_active(image_id):
|
||||
return full_path(image_id) == os.path.realpath(consts.SYMLINK)
|
||||
return full_path(image_id) == os.path.realpath(
|
||||
CONF.active_bootstrap_symlink)
|
||||
|
||||
|
||||
def full_path(image_id):
|
||||
if not os.path.isabs(image_id):
|
||||
return os.path.join(consts.BOOTSTRAP_IMAGES_DIR, image_id)
|
||||
return os.path.join(CONF.bootstrap_images_dir, image_id)
|
||||
return image_id
|
||||
|
||||
|
||||
|
@ -123,7 +125,7 @@ def extract_to_dir(arch_path, extract_path):
|
|||
|
||||
|
||||
def make_bootstrap(params):
|
||||
bootdata_builder = data_util.BootstrapDataBuilder(params)
|
||||
bootdata_builder = data_util.BootstrapDataBuilder(vars(params))
|
||||
bootdata = bootdata_builder.build()
|
||||
|
||||
LOG.info("Try to build image with data:\n%s", yaml.safe_dump(bootdata))
|
||||
|
@ -135,3 +137,5 @@ def make_bootstrap(params):
|
|||
'bootstrap_build_image', '--nodebug', '-v',
|
||||
'--image_build_dir', params.image_build_dir,
|
||||
'--input_data_file', f.name)
|
||||
|
||||
return bootdata['uuid'], bootdata['output']
|
||||
|
|
|
@ -19,54 +19,53 @@ import os
|
|||
import re
|
||||
import six
|
||||
import uuid
|
||||
import yaml
|
||||
|
||||
from fuel_bootstrap import consts
|
||||
from fuel_bootstrap import errors
|
||||
from fuel_bootstrap import settings
|
||||
|
||||
CONF = settings.Configuration()
|
||||
|
||||
|
||||
class BootstrapDataBuilder(object):
|
||||
|
||||
def __init__(self, data):
|
||||
self.astute = self._parse_astute()
|
||||
|
||||
self.uuid = six.text_type(uuid.uuid4())
|
||||
|
||||
self.container_format = consts.CONTAINER_FORMAT
|
||||
|
||||
self.ubuntu_release = data.ubuntu_release or consts.UBUNTU_RELEASE
|
||||
self.ubuntu_repo = data.ubuntu_repo
|
||||
self.mos_repo = data.mos_repo
|
||||
self.repos = data.repos or []
|
||||
self.ubuntu_release = \
|
||||
data.get('ubuntu_release') or \
|
||||
consts.UBUNTU_RELEASE
|
||||
|
||||
self.http_proxy = data.http_proxy or \
|
||||
self.astute['BOOTSTRAP']['HTTP_PROXY']
|
||||
self.https_proxy = data.https_proxy or \
|
||||
self.astute['BOOTSTRAP']['HTTPS_PROXY']
|
||||
self.direct_repo_addr = data.direct_repo_addr
|
||||
self.ubuntu_repo = data.get('ubuntu_repo')
|
||||
self.mos_repo = data.get('mos_repo')
|
||||
self.extra_repos = data.get('extra_repos') or []
|
||||
|
||||
self.post_script_file = data.post_script_file
|
||||
self.root_ssh_authorized_file = data.root_ssh_authorized_file
|
||||
self.extra_files = data.extra_files
|
||||
self.http_proxy = data.get('http_proxy') or CONF.http_proxy
|
||||
self.https_proxy = data.get('https_proxy') or CONF.https_proxy
|
||||
self.direct_repo_addr = data.get('direct_repo_addr')
|
||||
|
||||
self.include_kernel_module = data.include_kernel_module
|
||||
self.blacklist_kernel_module = data.blacklist_kernel_module
|
||||
self.post_script_file = \
|
||||
data.get('post_script_file') or \
|
||||
CONF.post_script_file
|
||||
self.root_ssh_authorized_file = \
|
||||
data.get('root_ssh_authorized_file') or \
|
||||
CONF.root_ssh_authorized_file
|
||||
self.extra_files = data.get('extra_files') or CONF.extra_files
|
||||
|
||||
self.packages = data.packages
|
||||
self.include_kernel_module = data.get('include_kernel_module')
|
||||
self.blacklist_kernel_module = data.get('blacklist_kernel_module')
|
||||
|
||||
self.label = data.label
|
||||
self.extend_kopts = data.extend_kopts
|
||||
self.kernel_flavor = data.kernel_flavor
|
||||
self.output = os.path.join(
|
||||
data.output_dir,
|
||||
"{uuid}.{format}".format(
|
||||
uuid=self.uuid,
|
||||
format=self.container_format))
|
||||
self.packages = data.get('packages')
|
||||
|
||||
def _parse_astute(self):
|
||||
with open(consts.ASTUTE_FILE) as f:
|
||||
data = yaml.safe_load(f)
|
||||
return data
|
||||
self.label = data.get('label') or self.uuid
|
||||
self.extend_kopts = data.get('extend_kopts')
|
||||
self.kernel_flavor = data.get('kernel_flavor')
|
||||
|
||||
file_name = "{0}.{1}".format(self.uuid, self.container_format)
|
||||
output_dir = data.get('output_dir', CONF.output_dir)
|
||||
self.output = os.path.join(output_dir, file_name)
|
||||
|
||||
def build(self):
|
||||
return {
|
||||
|
@ -113,7 +112,7 @@ class BootstrapDataBuilder(object):
|
|||
if self.direct_repo_addr:
|
||||
addrs |= set(self.direct_repo_addr)
|
||||
|
||||
addrs.add(self.astute['ADMIN_NETWORK']['ipaddress'])
|
||||
addrs |= set(CONF.direct_repo_adresses)
|
||||
|
||||
return list(addrs)
|
||||
|
||||
|
@ -122,27 +121,27 @@ class BootstrapDataBuilder(object):
|
|||
if self.ubuntu_repo:
|
||||
repos.extend(self._parse_ubuntu_repos(self.ubuntu_repo))
|
||||
else:
|
||||
repos.extend(self.astute['BOOTSTRAP']['MIRROR_DISTRO'])
|
||||
repos.extend(CONF.ubuntu_repos)
|
||||
|
||||
if self.mos_repo:
|
||||
repos.extend(self._parse_mos_repos(self.mos_repo))
|
||||
else:
|
||||
repos.extend(self.astute['BOOTSTRAP']['MIRROR_MOS'])
|
||||
repos.extend(CONF.mos_repos)
|
||||
|
||||
repo_count = 0
|
||||
for repo in self.repos:
|
||||
for repo in self.extra_repos:
|
||||
repo_count += 1
|
||||
repos.append(self._parse_repo(
|
||||
repo,
|
||||
name="extra_repo{0}".format(repo_count)))
|
||||
|
||||
if not self.repos:
|
||||
repos.extend(self.astute['BOOTSTRAP']['EXTRA_DEB_REPOS'])
|
||||
if not self.extra_repos:
|
||||
repos.extend(CONF.extra_repos)
|
||||
|
||||
return sorted(repos, key=lambda repo: repo['priority'] or 500)
|
||||
|
||||
def _get_packages(self):
|
||||
result = set(consts.DEFAULT_PACKAGES)
|
||||
result = set(CONF.packages)
|
||||
result.add(self.kernel_flavor)
|
||||
if self.packages:
|
||||
result |= set(self.packages)
|
||||
|
|
Loading…
Reference in New Issue