Add settings to fuel-bootstrap CLI

Change-Id: I2610333cf90827915786ee585fd9091c6ff9a17e
Implements: blueprint bootstrap-images-support-in-cli
This commit is contained in:
Artur Svechnikov 2015-11-25 17:14:34 +03:00
parent 283624a1a6
commit bd67efbada
7 changed files with 97 additions and 75 deletions

View File

@ -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))

View File

@ -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))

View File

@ -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"
]

View File

@ -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"""

View File

@ -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)

View File

@ -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']

View File

@ -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)