diff --git a/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/commands/build.py b/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/commands/build.py index b9be4d9..0609707 100644 --- a/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/commands/build.py +++ b/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/commands/build.py @@ -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)) diff --git a/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/commands/import.py b/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/commands/import.py index c4b83b8..39e0d93 100644 --- a/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/commands/import.py +++ b/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/commands/import.py @@ -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)) diff --git a/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/consts.py b/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/consts.py index 93dd0b2..0f8bfbd 100644 --- a/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/consts.py +++ b/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/consts.py @@ -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" -] diff --git a/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/errors.py b/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/errors.py index 6be18f6..bd39a3a 100644 --- a/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/errors.py +++ b/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/errors.py @@ -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""" diff --git a/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/settings.py b/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/settings.py new file mode 100644 index 0000000..def366a --- /dev/null +++ b/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/settings.py @@ -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) diff --git a/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/utils/bootstrap_image.py b/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/utils/bootstrap_image.py index 023e155..524ec73 100644 --- a/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/utils/bootstrap_image.py +++ b/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/utils/bootstrap_image.py @@ -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'] diff --git a/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/utils/data.py b/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/utils/data.py index 7155f84..c7bd122 100644 --- a/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/utils/data.py +++ b/contrib/fuel_bootstrap/fuel_bootstrap_cli/fuel_bootstrap/utils/data.py @@ -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)