kayobe/kayobe/cli/commands.py

331 lines
14 KiB
Python

import json
import platform
import sys
from cliff.command import Command
from kayobe import ansible
from kayobe import kolla_ansible
from kayobe import utils
def _build_playbook_list(*playbooks):
"""Return a list of names of playbook files given their basenames."""
return ["ansible/%s.yml" % playbook for playbook in playbooks]
class KayobeAnsibleMixin(object):
"""Mixin class for commands running Kayobe Ansible playbooks."""
def get_parser(self, prog_name):
parser = super(KayobeAnsibleMixin, self).get_parser(prog_name)
group = parser.add_argument_group("Kayobe Ansible")
self.add_kayobe_ansible_args(group)
return parser
def add_kayobe_ansible_args(self, group):
ansible.add_args(group)
class KollaAnsibleMixin(object):
"""Mixin class for commands running Kolla Ansible."""
def get_parser(self, prog_name):
parser = super(KollaAnsibleMixin, self).get_parser(prog_name)
group = parser.add_argument_group("Kolla Ansible")
self.add_kolla_ansible_args(group)
return parser
def add_kolla_ansible_args(self, group):
kolla_ansible.add_args(group)
class ControlHostBootstrap(KayobeAnsibleMixin, Command):
"""Bootstrap the Kayobe control environment."""
def take_action(self, parsed_args):
self.app.LOG.debug("Bootstrapping Kayobe control host")
linux_distname = platform.linux_distribution()[0]
if linux_distname == "CentOS Linux":
utils.yum_install(["epel-release"])
else:
# On RHEL, the following should be done to install EPEL:
# sudo subscription-manager repos --enable=qci-1.0-for-rhel-7-rpms
# if ! yum info epel-release >/dev/null 2>&1 ; then
# sudo yum -y install \
# https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
# fi
self.app.LOG.error("%s is not currently supported", linux_distname)
sys.exit(1)
utils.yum_install(["ansible"])
utils.galaxy_install("ansible/requirements.yml", "ansible/roles")
playbooks = _build_playbook_list("bootstrap", "kolla")
ansible.run_playbooks(parsed_args, playbooks)
class ConfigurationDump(KayobeAnsibleMixin, Command):
"""Dump Kayobe configuration."""
def get_parser(self, prog_name):
parser = super(ConfigurationDump, self).get_parser(prog_name)
group = parser.add_argument_group("Configuration Dump")
group.add_argument("--dump-facts", default=False,
help="whether to gather and dump host facts")
group.add_argument("--host",
help="name of a host to dump config for")
group.add_argument("--hosts",
help="name of hosts and/or groups to dump config "
"for")
group.add_argument("--var-name",
help="name of a variable to dump")
return parser
def take_action(self, parsed_args):
self.app.LOG.debug("Dumping Ansible configuration")
hostvars = ansible.config_dump(parsed_args,
host=parsed_args.host,
hosts=parsed_args.hosts,
facts=parsed_args.dump_facts,
var_name=parsed_args.var_name)
try:
json.dump(hostvars, sys.stdout, sort_keys=True, indent=4)
except TypeError as e:
self.app.LOG.error("Failed to JSON encode configuration: %s",
repr(e))
sys.exit(1)
class PlaybookRun(KayobeAnsibleMixin, Command):
"""Run a Kayobe Ansible playbook."""
def add_kayobe_ansible_args(self, group):
super(PlaybookRun, self).add_kayobe_ansible_args(group)
group.add_argument("playbook", nargs="+",
help="name of the playbook(s) to run")
def take_action(self, parsed_args):
self.app.LOG.debug("Running Kayobe playbook(s)")
ansible.run_playbooks(parsed_args, parsed_args.playbook)
class KollaAnsibleRun(KollaAnsibleMixin, Command):
"""Run a Kolla Ansible command."""
def add_kolla_ansible_args(self, group):
super(KollaAnsibleRun, self).add_kolla_ansible_args(group)
group.add_argument("--kolla-inventory-filename", default="overcloud",
choices=["seed", "overcloud"],
help="name of the kolla-ansible inventory file, "
"one of seed or overcloud (default "
"overcloud)")
group.add_argument("command",
help="name of the kolla-ansible command to run")
def take_action(self, parsed_args):
self.app.LOG.debug("Running Kolla Ansible command")
kolla_ansible.run(parsed_args, parsed_args.command,
parsed_args.kolla_inventory_filename)
class PhysicalNetworkConfigure(KayobeAnsibleMixin, Command):
"""Configure a set of physical network devices."""
def get_parser(self, prog_name):
parser = super(PhysicalNetworkConfigure, self).get_parser(
prog_name)
group = parser.add_argument_group("Physical Networking")
group.add_argument("--group", required=True,
help="the Ansible group to apply configuration to")
return parser
def take_action(self, parsed_args):
self.app.LOG.debug("Configuring a physical network")
ansible.run_playbook(parsed_args, "ansible/physical-network.yml",
limit=parsed_args.group)
class SeedVMProvision(KollaAnsibleMixin, KayobeAnsibleMixin, Command):
"""Provision the seed VM."""
def take_action(self, parsed_args):
self.app.LOG.debug("Provisioning seed VM")
ansible.run_playbook(parsed_args, "ansible/ip-allocation.yml",
limit="seed")
ansible.run_playbook(parsed_args, "ansible/seed-vm.yml")
# Now populate the Kolla Ansible inventory.
ansible.run_playbook(parsed_args, "ansible/kolla-ansible.yml",
tags="config")
class SeedHostConfigure(KollaAnsibleMixin, KayobeAnsibleMixin, Command):
"""Configure the seed node host OS."""
def get_parser(self, prog_name):
parser = super(SeedHostConfigure, self).get_parser(prog_name)
group = parser.add_argument_group("Host Configuration")
group.add_argument("--wipe-disks", action='store_true',
help="wipe partition and LVM data from all disks "
"that are not mounted. Warning: this can "
"result in the loss of data")
return parser
def take_action(self, parsed_args):
self.app.LOG.debug("Configuring seed host OS")
ansible_user = ansible.config_dump(parsed_args, host="seed",
var_name="kayobe_ansible_user")
playbooks = _build_playbook_list(
"ip-allocation", "ssh-known-host", "kayobe-ansible-user")
if parsed_args.wipe_disks:
playbooks += _build_playbook_list("disk-wipe")
playbooks += _build_playbook_list(
"dev-tools", "disable-selinux", "network", "ntp", "lvm")
ansible.run_playbooks(parsed_args, playbooks, limit="seed")
kolla_ansible.run_seed(parsed_args, "bootstrap-servers",
extra_vars={"ansible_user": ansible_user})
playbooks = _build_playbook_list("kolla-host", "docker")
ansible.run_playbooks(parsed_args, playbooks, limit="seed")
class SeedServiceDeploy(KollaAnsibleMixin, KayobeAnsibleMixin, Command):
"""Deploy the seed services."""
def take_action(self, parsed_args):
self.app.LOG.debug("Deploying seed services")
ansible.run_playbook(parsed_args, "ansible/kolla-bifrost.yml")
kolla_ansible.run_seed(parsed_args, "deploy-bifrost")
playbooks = _build_playbook_list(
"seed-introspection-rules", "dell-switch-bmp")
ansible.run_playbooks(parsed_args, playbooks)
class SeedContainerImageBuild(KayobeAnsibleMixin, Command):
"""Build the seed container images."""
def get_parser(self, prog_name):
parser = super(SeedContainerImageBuild, self).get_parser(
prog_name)
group = parser.add_argument_group("Container Image Build")
group.add_argument("--push", action="store_true",
help="whether to push images to a registry after "
"building")
return parser
def take_action(self, parsed_args):
self.app.LOG.debug("Building seed container images")
playbooks = _build_playbook_list(
"kolla-build", "container-image-build")
extra_vars = {"push_images": parsed_args.push}
ansible.run_playbooks(parsed_args, playbooks, limit="seed",
extra_vars=extra_vars)
class OvercloudInventoryDiscover(KayobeAnsibleMixin, Command):
"""Discover the overcloud inventory from the seed's Ironic service."""
def take_action(self, parsed_args):
self.app.LOG.debug("Discovering overcloud inventory")
# Run the inventory discovery playbook separately, else the discovered
# hosts will not be present in the following playbooks in which they
# are used to populate other inventories.
ansible.run_playbook(parsed_args,
"ansible/overcloud-inventory-discover.yml")
# Now populate the Kolla Ansible and Bifrost inventories.
ansible.run_playbook(parsed_args, "ansible/kolla-bifrost-hostvars.yml")
ansible.run_playbook(parsed_args, "ansible/kolla-ansible.yml",
tags="config")
class OvercloudProvision(KayobeAnsibleMixin, Command):
"""Provision the overcloud."""
def take_action(self, parsed_args):
self.app.LOG.debug("Provisioning overcloud")
self._configure_network(parsed_args)
self._configure_bios_and_raid(parsed_args)
self._deploy_servers(parsed_args)
def _configure_network(self, parsed_args):
self.app.LOG.debug("TODO: configure overcloud network")
def _configure_bios_and_raid(self, parsed_args):
self.app.LOG.debug("TODO: configure overcloud BIOS and RAID")
def _deploy_servers(self, parsed_args):
self.app.LOG.debug("Deploying overcloud servers via Bifrost")
ansible.run_playbook(parsed_args,
"ansible/overcloud-provision.yml")
class OvercloudDeprovision(KayobeAnsibleMixin, Command):
"""Deprovision the overcloud."""
def take_action(self, parsed_args):
self.app.LOG.debug("Deprovisioning overcloud")
ansible.run_playbook(parsed_args,
"ansible/overcloud-deprovision.yml")
class OvercloudHostConfigure(KollaAnsibleMixin, KayobeAnsibleMixin, Command):
"""Configure the overcloud host OS."""
def get_parser(self, prog_name):
parser = super(OvercloudHostConfigure, self).get_parser(prog_name)
group = parser.add_argument_group("Host Configuration")
group.add_argument("--wipe-disks", action='store_true',
help="wipe partition and LVM data from all disks "
"that are not mounted. Warning: this can "
"result in the loss of data")
return parser
def take_action(self, parsed_args):
self.app.LOG.debug("Configuring overcloud host OS")
ansible_user = ansible.config_dump(parsed_args, host="controllers[0]",
var_name="kayobe_ansible_user")
playbooks = _build_playbook_list(
"ip-allocation", "ssh-known-host", "kayobe-ansible-user")
if parsed_args.wipe_disks:
playbooks += _build_playbook_list("disk-wipe")
playbooks += _build_playbook_list(
"dev-tools", "disable-selinux", "network", "ntp", "lvm")
ansible.run_playbooks(parsed_args, playbooks, limit="controllers")
kolla_ansible.run_overcloud(parsed_args, "bootstrap-servers",
extra_vars={"ansible_user": ansible_user})
playbooks = _build_playbook_list("kolla-host", "docker")
ansible.run_playbooks(parsed_args, playbooks, limit="controllers")
class OvercloudServiceDeploy(KollaAnsibleMixin, KayobeAnsibleMixin, Command):
"""Deploy the overcloud services."""
def take_action(self, parsed_args):
self.app.LOG.debug("Deploying overcloud services")
playbooks = _build_playbook_list("kolla-openstack", "swift-setup")
ansible.run_playbooks(parsed_args, playbooks)
for command in ["pull", "prechecks", "deploy"]:
kolla_ansible.run_overcloud(parsed_args, command)
# FIXME: Fudge to work around incorrect configuration path.
extra_vars = {"node_config_directory": parsed_args.kolla_config_path}
kolla_ansible.run_overcloud(parsed_args, "post-deploy",
extra_vars=extra_vars)
class OvercloudContainerImageBuild(KayobeAnsibleMixin, Command):
"""Build the overcloud container images."""
def get_parser(self, prog_name):
parser = super(OvercloudContainerImageBuild, self).get_parser(
prog_name)
group = parser.add_argument_group("Container Image Build")
group.add_argument("--push", action="store_true",
help="whether to push images to a registry after "
"building")
return parser
def take_action(self, parsed_args):
self.app.LOG.debug("Building overcloud container images")
playbooks = _build_playbook_list(
"kolla-build", "container-image-build")
extra_vars = {"push_images": parsed_args.push}
ansible.run_playbooks(parsed_args, playbooks, limit="controllers",
extra_vars=extra_vars)