Remove unused integrations: os_faults and ansible
Change-Id: I6fe7f699b8886171f749ee63ebec62a1c09ebd3e
This commit is contained in:
parent
135de24450
commit
eafecdd050
@ -1,6 +1,5 @@
|
||||
# Tobiko framework requirements
|
||||
|
||||
ansible>=2.4.0,<2.8.0 # GPLv3
|
||||
docker>=4.0 # Apache-2.0
|
||||
podman>=1.6.0 # Apache-2.0
|
||||
fixtures>=3.0.0 # Apache-2.0/BSD
|
||||
@ -9,7 +8,6 @@ Jinja2>=2.8.0 # BSD
|
||||
junitxml>=0.7 # MIT
|
||||
netaddr>=0.7.18 # BSD
|
||||
neutron-lib>=1.25.0 # Apache-2.0
|
||||
os-faults>=0.1.18 # Apache-2.0
|
||||
oslo.config>=5.2.0 # Apache-2.0
|
||||
oslo.log>=3.36.0 # Apache-2.0
|
||||
pandas>=0.24.2 # BSD
|
||||
|
@ -27,13 +27,8 @@ packages =
|
||||
|
||||
[entry_points]
|
||||
console_scripts =
|
||||
tobiko-create = tobiko.cmd.create:main
|
||||
tobiko-delete = tobiko.cmd.delete:main
|
||||
tobiko-fixture = tobiko.cmd.fixture:main
|
||||
tobiko-keystone-credentials = tobiko.openstack.keystone._credentials:print_credentials
|
||||
tobiko-list = tobiko.cmd.list:main
|
||||
tobiko-fault = tobiko.cmd.fault:main
|
||||
tobiko = tobiko.cmd.run:main
|
||||
oslo.config.opts =
|
||||
tobiko = tobiko.config:list_tobiko_options
|
||||
|
||||
|
@ -14,13 +14,11 @@
|
||||
# under the License.
|
||||
from __future__ import absolute_import
|
||||
|
||||
import os
|
||||
import logging
|
||||
import argparse
|
||||
|
||||
from oslo_log import log
|
||||
|
||||
from tobiko.common.managers import ansible
|
||||
from tobiko import config
|
||||
|
||||
|
||||
@ -36,11 +34,6 @@ class TobikoCMD(object):
|
||||
self.parser = self.get_parser()
|
||||
self.args = (self.parser).parse_args()
|
||||
|
||||
curr_dir = os.path.dirname(__file__)
|
||||
self.playbooks_dir = os.path.join(curr_dir,
|
||||
"../tests/scenario/playbooks")
|
||||
self.ansibleManager = ansible.AnsibleManager(self.playbooks_dir)
|
||||
|
||||
def get_parser(self):
|
||||
parser = argparse.ArgumentParser(add_help=True)
|
||||
parser.add_argument('--verbose', '-v', action='count',
|
||||
|
@ -1,54 +0,0 @@
|
||||
# Copyright 2018 Red Hat
|
||||
#
|
||||
# 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.
|
||||
from __future__ import absolute_import
|
||||
|
||||
import sys
|
||||
|
||||
from oslo_log import log
|
||||
|
||||
import tobiko
|
||||
from tobiko.cmd import base
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class CreateUtil(base.TobikoCMD):
|
||||
|
||||
def get_parser(self):
|
||||
parser = super(CreateUtil, self).get_parser()
|
||||
parser.add_argument(
|
||||
'--playbook', '-p',
|
||||
help="The name of the playbook to execute.\n"
|
||||
"This is based on the playbook name in playbooks dir")
|
||||
return parser
|
||||
|
||||
def run_playbook(self, playbook):
|
||||
"""Executes given playbook."""
|
||||
self.ansibleManager.run_playbook(playbook, mode='create')
|
||||
|
||||
|
||||
class NoSuchTemplateError(tobiko.TobikoException):
|
||||
message = "no such template; existing templates are: {templates}"
|
||||
|
||||
|
||||
def main():
|
||||
"""Create CLI main entry."""
|
||||
create_cmd = CreateUtil()
|
||||
create_cmd.set_stream_handler_logging_level()
|
||||
if create_cmd.args.playbook:
|
||||
create_cmd.run_playbook(create_cmd.args.playbook)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
@ -1,46 +0,0 @@
|
||||
# Copyright 2018 Red Hat
|
||||
#
|
||||
# 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.
|
||||
from __future__ import absolute_import
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from tobiko.cmd import base
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DeleteUtil(base.TobikoCMD):
|
||||
|
||||
def get_parser(self):
|
||||
parser = super(DeleteUtil, self).get_parser()
|
||||
parser.add_argument(
|
||||
'--playbook', '-p',
|
||||
help="The name of the playbook to execute in delete mode.")
|
||||
return parser
|
||||
|
||||
def run_playbook(self, playbook):
|
||||
"""Executes given playbook."""
|
||||
self.ansibleManager.run_playbook(playbook, mode='delete')
|
||||
|
||||
|
||||
def main():
|
||||
"""Delete CLI main entry."""
|
||||
delete_cmd = DeleteUtil()
|
||||
delete_cmd.set_stream_handler_logging_level()
|
||||
delete_cmd.run_playbook(delete_cmd.args.playbook)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
@ -1,59 +0,0 @@
|
||||
# Copyright 2019 Red Hat
|
||||
#
|
||||
# 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.
|
||||
from __future__ import absolute_import
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from tobiko.openstack import os_faults
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FaultCMD(object):
|
||||
|
||||
def __init__(self):
|
||||
self.parser = self.get_parser()
|
||||
self.args = self.parser.parse_args()
|
||||
|
||||
def get_parser(self):
|
||||
parser = argparse.ArgumentParser(add_help=True)
|
||||
parser.add_argument(
|
||||
'fault',
|
||||
help="The fault to execute (e.g. restart neutron service).\n")
|
||||
return parser
|
||||
|
||||
def run(self):
|
||||
"""Run faults."""
|
||||
os_faults.os_faults_execute(self.args.fault)
|
||||
|
||||
|
||||
def setup_logging(debug=None):
|
||||
"""Sets the logging."""
|
||||
# pylint: disable=W0622
|
||||
level = logging.DEBUG if debug else logging.INFO
|
||||
logging.basicConfig(level=level, format='%(message)s')
|
||||
|
||||
|
||||
def main():
|
||||
"""Run CLI main entry."""
|
||||
setup_logging()
|
||||
fault_cli = FaultCMD()
|
||||
fault_cli.run()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
@ -1,57 +0,0 @@
|
||||
# Copyright 2018 Red Hat
|
||||
#
|
||||
# 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.
|
||||
from __future__ import absolute_import
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from tobiko.cmd import base
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ListUtil(base.TobikoCMD):
|
||||
|
||||
def __init__(self):
|
||||
super(ListUtil, self).__init__()
|
||||
self.parser = self.get_parser()
|
||||
self.args = (self.parser).parse_args()
|
||||
|
||||
def get_parser(self):
|
||||
parser = argparse.ArgumentParser(add_help=True)
|
||||
parser.add_argument('--playbooks', '-p',
|
||||
help="List playbooks provided by Tobiko",
|
||||
const='list_playbooks',
|
||||
action='store_const', dest='action')
|
||||
return parser
|
||||
|
||||
def list_playbooks(self):
|
||||
"""Lists playbooks included in Tobiko."""
|
||||
for playbook in self.ansibleManager.get_playbooks_names():
|
||||
sys.stdout.write(playbook + '\n')
|
||||
|
||||
|
||||
def main():
|
||||
"""List CLI main entry."""
|
||||
list_cmd = ListUtil()
|
||||
if list_cmd.args.action:
|
||||
action_func = getattr(list_cmd, list_cmd.args.action)
|
||||
action_func()
|
||||
else:
|
||||
list_cmd.list_playbooks()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
@ -1,60 +0,0 @@
|
||||
# Copyright 2018 Red Hat
|
||||
#
|
||||
# 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.
|
||||
from __future__ import absolute_import
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
import paramiko
|
||||
|
||||
from oslo_log import log
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class Tobiko():
|
||||
|
||||
def __init__(self):
|
||||
self.parser = self.get_parser()
|
||||
self.args = (self.parser).parse_args()
|
||||
self.ssh = paramiko.SSHClient()
|
||||
self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
|
||||
def get_parser(self):
|
||||
parser = argparse.ArgumentParser(add_help=True)
|
||||
parser.add_argument(
|
||||
'--host',
|
||||
help="The name of the host where your cloud is deployed.\n")
|
||||
parser.add_argument(
|
||||
'--key', '-k',
|
||||
help="They SSH key to use to connect the host.")
|
||||
return parser
|
||||
|
||||
def verify_connection(self):
|
||||
"""Verifies it's able to connect the host provided by the user."""
|
||||
try:
|
||||
self.ssh.connect(self.args.host)
|
||||
except paramiko.ssh_exception.AuthenticationException:
|
||||
LOG.error("Unable to connect %r", self.args.host)
|
||||
|
||||
|
||||
def main():
|
||||
"""Run CLI main entry."""
|
||||
tobiko = Tobiko()
|
||||
tobiko.verify_connection()
|
||||
# run.discover_environment()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
@ -1,98 +0,0 @@
|
||||
# Copyright 2018 Red Hat
|
||||
#
|
||||
# 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.
|
||||
from __future__ import absolute_import
|
||||
|
||||
from collections import namedtuple
|
||||
import os
|
||||
|
||||
from ansible.executor import playbook_executor
|
||||
from ansible.inventory.manager import InventoryManager
|
||||
from ansible.parsing.dataloader import DataLoader
|
||||
from ansible.vars.manager import VariableManager
|
||||
from oslo_log import log
|
||||
|
||||
from tobiko import config
|
||||
from tobiko.openstack import keystone
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
TEMPLATE_SUFFIX = ".yaml"
|
||||
|
||||
|
||||
class AnsibleManager(object):
|
||||
"""Manages Ansible entities."""
|
||||
|
||||
def __init__(self, playbooks_dir):
|
||||
self.playbooks_dir = playbooks_dir
|
||||
self.loader = DataLoader()
|
||||
self.inventory = InventoryManager(loader=self.loader,
|
||||
sources='localhost,')
|
||||
self.variable_manager = VariableManager(loader=self.loader,
|
||||
inventory=self.inventory)
|
||||
self.options = self.get_options()
|
||||
self.passwords = dict(vault_pass='secret')
|
||||
|
||||
def get_playbooks_names(self, strip_suffix=False):
|
||||
"""Returns a list of all the files in playbooks dir."""
|
||||
playbooks = []
|
||||
for (_, _, files) in os.walk(self.playbooks_dir):
|
||||
playbooks.extend(files)
|
||||
if strip_suffix:
|
||||
playbooks = [
|
||||
f[:-len(TEMPLATE_SUFFIX)] for f in playbooks]
|
||||
return playbooks
|
||||
|
||||
def get_options(self):
|
||||
"""Returns namedtuple of Ansible options."""
|
||||
Options = namedtuple('Options', ['connection', 'module_path',
|
||||
'forks', 'become', 'become_method',
|
||||
'become_user', 'check', 'diff',
|
||||
'listhosts', 'listtasks',
|
||||
'listtags', 'syntax'])
|
||||
|
||||
options = Options(connection='local', module_path=['/to/mymodules'],
|
||||
forks=10, become=None, become_method=None,
|
||||
become_user=None, check=False, diff=False,
|
||||
listhosts=False,
|
||||
listtasks=False, listtags=False, syntax=False)
|
||||
|
||||
return options
|
||||
|
||||
def run_playbook(self, playbook, mode='create'):
|
||||
"""Executes given playbook."""
|
||||
playbook_path = self.playbooks_dir + '/' + playbook
|
||||
|
||||
credentials = keystone.default_keystone_credentials()
|
||||
extra_vars = {'mode': mode,
|
||||
'auth_url': credentials.auth_url,
|
||||
'username': credentials.username,
|
||||
'project_name': credentials.project_name,
|
||||
'password': credentials.project_name.password,
|
||||
'image': CONF.tobiko.glance.cirros_image,
|
||||
'flavor': CONF.tobiko.nova.flavor}
|
||||
|
||||
self.variable_manager.extra_vars = extra_vars
|
||||
|
||||
pb_executor = playbook_executor.PlaybookExecutor(
|
||||
playbooks=[playbook_path],
|
||||
inventory=self.inventory,
|
||||
variable_manager=self.variable_manager,
|
||||
loader=self.loader,
|
||||
options=self.options,
|
||||
passwords=self.passwords)
|
||||
|
||||
pb_executor.run()
|
@ -1,72 +0,0 @@
|
||||
# Copyright 2018 Red Hat
|
||||
#
|
||||
# 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.
|
||||
from __future__ import absolute_import
|
||||
|
||||
import os
|
||||
|
||||
import os_faults
|
||||
import yaml
|
||||
|
||||
from oslo_log import log
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
try:
|
||||
FileNotFoundError
|
||||
except NameError:
|
||||
FileNotFoundError = IOError # pylint: disable=redefined-builtin
|
||||
|
||||
CONF_DIR = os.path.expanduser('~')
|
||||
CONF_FILE = 'os-faults.yaml'
|
||||
|
||||
|
||||
class FaultManager():
|
||||
"""Manages faults."""
|
||||
|
||||
def __init__(self, test_file):
|
||||
self.faults_dir = os.path.join(os.path.dirname(test_file), 'faults')
|
||||
faults_f_name = os.path.splitext(os.path.basename(test_file))[0]
|
||||
self.faults_file = os.path.join(self.faults_dir, faults_f_name)
|
||||
fault_config_f = os.path.join(CONF_DIR, CONF_FILE)
|
||||
try:
|
||||
self.cloud = os_faults.connect(config_filename=fault_config_f)
|
||||
self.cloud.verify()
|
||||
self.scenarios = self.get_scenarios()
|
||||
except os_faults.ansible.executor.AnsibleExecutionUnreachable:
|
||||
LOG.warning("Couldn't verify connectivity to the"
|
||||
" cloud with os-faults configuration")
|
||||
self.scenarios = None
|
||||
except FileNotFoundError:
|
||||
LOG.warning("Couldn't find os-faults configuration file")
|
||||
self.scenarios = None
|
||||
|
||||
def get_scenarios(self):
|
||||
"""Returns list of scenarios based on defined faults.
|
||||
|
||||
A scenario composed out of scenario name and the fault to execute.
|
||||
"""
|
||||
scenarios = []
|
||||
with open(self.faults_file, 'r') as stream:
|
||||
faults_yaml = yaml.load(stream)
|
||||
for fault in faults_yaml:
|
||||
scenarios.append((fault['name'], dict(fault=fault['action'])))
|
||||
return scenarios
|
||||
|
||||
def run_fault(self, fault):
|
||||
"""Executes given fault."""
|
||||
if self.scenarios:
|
||||
os_faults.human_api(self.cloud, fault)
|
||||
else:
|
||||
LOG.debug("Skipped fault: '{}' since".format(fault),
|
||||
" scenarios are not defined.")
|
@ -35,7 +35,6 @@ CONFIG_MODULES = ['tobiko.openstack.glance.config',
|
||||
'tobiko.openstack.neutron.config',
|
||||
'tobiko.openstack.nova.config',
|
||||
'tobiko.openstack.octavia.config',
|
||||
'tobiko.openstack.os_faults.config',
|
||||
'tobiko.openstack.topology.config',
|
||||
'tobiko.shell.ssh.config',
|
||||
'tobiko.shell.ping.config',
|
||||
|
@ -1,25 +0,0 @@
|
||||
# Copyright 2019 Red Hat
|
||||
#
|
||||
# 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.
|
||||
from __future__ import absolute_import
|
||||
|
||||
from tobiko.openstack.os_faults import _config_file
|
||||
from tobiko.openstack.os_faults import _cloud
|
||||
from tobiko.openstack.os_faults import _execute
|
||||
|
||||
get_os_fault_cloud_managenemt = _cloud.get_os_fault_cloud_managenemt
|
||||
OsFaultsCloudManagementFixture = _cloud.OsFaultsCloudManagementFixture
|
||||
|
||||
get_os_fault_config_filename = _config_file.get_os_fault_config_filename
|
||||
|
||||
os_faults_execute = _execute.os_faults_execute
|
@ -1,58 +0,0 @@
|
||||
# Copyright 2019 Red Hat
|
||||
#
|
||||
# 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.
|
||||
from __future__ import absolute_import
|
||||
|
||||
import os_faults
|
||||
from oslo_log import log
|
||||
|
||||
import tobiko
|
||||
from tobiko.openstack.os_faults import _config_file
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
def get_os_fault_cloud_managenemt(config_filename=None):
|
||||
fixture = OsFaultsCloudManagementFixture(config_filename=config_filename)
|
||||
return tobiko.setup_fixture(fixture).cloud_management
|
||||
|
||||
|
||||
class OsFaultsCloudManagementFixture(tobiko.SharedFixture):
|
||||
"""Responsible for executing faults."""
|
||||
|
||||
config_filename = None
|
||||
cloud_management = None
|
||||
|
||||
def __init__(self, config_filename=None, cloud_management=None):
|
||||
super(OsFaultsCloudManagementFixture, self).__init__()
|
||||
if config_filename:
|
||||
self.config_filename = config_filename
|
||||
if cloud_management:
|
||||
self.cloud_management = cloud_management
|
||||
|
||||
def setup_fixture(self):
|
||||
self.connect()
|
||||
|
||||
def connect(self):
|
||||
"""Connect to the cloud using os-faults."""
|
||||
cloud_management = self.cloud_management
|
||||
if cloud_management is None:
|
||||
config_filename = self.config_filename
|
||||
if config_filename is None:
|
||||
self.config_filename = config_filename = (
|
||||
_config_file.get_os_fault_config_filename())
|
||||
LOG.info("OS-Faults: connecting with config filename %s",
|
||||
config_filename)
|
||||
self.cloud_management = cloud_management = os_faults.connect(
|
||||
config_filename=config_filename)
|
||||
return cloud_management
|
@ -1,240 +0,0 @@
|
||||
# Copyright 2019 Red Hat
|
||||
#
|
||||
# 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.
|
||||
from __future__ import absolute_import
|
||||
|
||||
import os
|
||||
import typing # noqa
|
||||
|
||||
import jinja2
|
||||
import six
|
||||
|
||||
from oslo_log import log
|
||||
|
||||
import tobiko
|
||||
from tobiko.openstack.os_faults import _exception
|
||||
from tobiko.openstack import topology
|
||||
from tobiko.shell import ssh
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
def get_os_fault_config_filename():
|
||||
return tobiko.setup_fixture(OsFaultsConfigFileFixture).config_filename
|
||||
|
||||
|
||||
class OsFaultsConfigFileFixture(tobiko.SharedFixture):
|
||||
"""Responsible for managing faults configuration."""
|
||||
|
||||
config = None
|
||||
config_filename = None
|
||||
template_filename = None
|
||||
topo = None
|
||||
|
||||
def __init__(self, config=None, config_filename=None,
|
||||
template_filename=None, topo=None):
|
||||
super(OsFaultsConfigFileFixture, self).__init__()
|
||||
self.templates_dir = os.path.join(os.path.dirname(__file__),
|
||||
'templates')
|
||||
if config is not None:
|
||||
self.config = config
|
||||
if config_filename is not None:
|
||||
self.config_filename = config_filename
|
||||
if template_filename is not None:
|
||||
self.template_filename = template_filename
|
||||
if topo:
|
||||
self.topo = topo
|
||||
|
||||
def setup_fixture(self):
|
||||
_config = self.config
|
||||
if not _config:
|
||||
from tobiko import config
|
||||
CONF = config.CONF
|
||||
self.config = _config = CONF.tobiko.os_faults
|
||||
self.config_filename = config_filename = self.get_config_filename()
|
||||
if config_filename is None:
|
||||
self.config_filename = self.generate_config_file(
|
||||
config_filename=config_filename)
|
||||
|
||||
def get_config_filename(self):
|
||||
config_filename = self.config_filename
|
||||
if config_filename is None:
|
||||
config_filename = os.environ.get('OS_FAULTS_CONFIG') or None
|
||||
|
||||
if config_filename is None:
|
||||
config_dirnames = self.config.config_dirnames
|
||||
config_filenames = self.config.config_filenames
|
||||
for dirname in config_dirnames:
|
||||
dirname = os.path.realpath(os.path.expanduser(dirname))
|
||||
for filename in config_filenames:
|
||||
filename = os.path.join(dirname, filename)
|
||||
if os.path.isfile(filename):
|
||||
config_filename = filename
|
||||
break
|
||||
|
||||
if config_filename is None:
|
||||
LOG.warning("Unable to find any of 'os_faults' files (%s) in "
|
||||
"any directory (%s",
|
||||
', '.join(config_filenames),
|
||||
', '.join(config_dirnames))
|
||||
return config_filename
|
||||
|
||||
def get_template_filename(self):
|
||||
template_filename = self.template_filename
|
||||
if template_filename is None:
|
||||
template_filename = os.environ.get('OS_FAULTS_TEMPLATE') or None
|
||||
|
||||
if template_filename is None:
|
||||
template_dirnames = self.config.template_dirnames
|
||||
config_filenames = self.config.config_filenames
|
||||
template_filenames = [filename + '.j2'
|
||||
for filename in config_filenames]
|
||||
for dirname in template_dirnames:
|
||||
dirname = os.path.realpath(os.path.expanduser(dirname))
|
||||
for filename in template_filenames:
|
||||
filename = os.path.join(dirname, filename)
|
||||
if os.path.isfile(filename):
|
||||
template_filename = filename
|
||||
break
|
||||
|
||||
if template_filename is None:
|
||||
LOG.warning("Unable to find any of 'os_faults' template file "
|
||||
"(%s) in any directory (%s").format(
|
||||
', '.join(template_filenames),
|
||||
', '.join(template_dirnames))
|
||||
return template_filename
|
||||
|
||||
def generate_config_file(self, config_filename):
|
||||
"""Generates os-faults configuration file."""
|
||||
|
||||
self.template_filename = template_filename = (
|
||||
self.get_template_filename())
|
||||
template_basename = os.path.basename(template_filename)
|
||||
if config_filename is None:
|
||||
config_dirname = os.path.realpath(
|
||||
os.path.expanduser(self.config.generate_config_dirname))
|
||||
config_basename, template_ext = os.path.splitext(template_basename)
|
||||
assert template_ext == '.j2'
|
||||
config_filename = os.path.join(config_dirname, config_basename)
|
||||
else:
|
||||
config_dirname = os.path.dirname(config_filename)
|
||||
|
||||
LOG.info("Generating os-fault config file from template %r to %r.",
|
||||
template_filename, config_filename)
|
||||
tobiko.makedirs(config_dirname)
|
||||
|
||||
make_os_faults_config_file(config_filename=config_filename,
|
||||
template_filename=template_filename,
|
||||
topo=self.topo)
|
||||
return config_filename
|
||||
|
||||
|
||||
def make_os_faults_config_file(config_filename, template_filename, topo=None):
|
||||
# type: (str, str, topology.OpenStackTopology) -> int
|
||||
template = get_os_faults_config_template(template_filename)
|
||||
config_content = get_os_faults_config_content(template=template, topo=topo)
|
||||
with tobiko.open_output_file(config_filename) as stream:
|
||||
LOG.debug('Write os-foults config file to %r:\n%s', config_filename,
|
||||
config_content)
|
||||
return stream.write(config_content)
|
||||
|
||||
|
||||
def get_os_faults_config_template(filename):
|
||||
# type: (str) -> jinja2.Template
|
||||
basename = os.path.basename(filename)
|
||||
dirname = os.path.dirname(filename)
|
||||
loader = jinja2.FileSystemLoader(dirname)
|
||||
environment = jinja2.Environment(loader=loader, trim_blocks=True)
|
||||
return environment.get_template(basename)
|
||||
|
||||
|
||||
def get_os_faults_config_content(template, topo=None):
|
||||
# type: (jinja2.Template, topology.OpenStackTopology) -> typing.Text
|
||||
topo = topo or topology.get_openstack_topology()
|
||||
nodes = [get_os_faults_node_from_topology(node) for node in topo.nodes]
|
||||
# TODO: get services and containers from OpenStack topology
|
||||
services = [] # type: typing.List[str]
|
||||
containers = [] # type: typing.List[str]
|
||||
return template.render(nodes=nodes,
|
||||
services=services,
|
||||
containers=containers)
|
||||
|
||||
|
||||
def get_os_faults_node_from_topology(node):
|
||||
# type: (topology.OpenStackTopologyNode) -> typing.Dict
|
||||
return {'fqdn': node.name,
|
||||
'ip': str(node.ssh_parameters['hostname']),
|
||||
'auth': get_os_faults_node_auth_from_topology(node)}
|
||||
|
||||
|
||||
def get_os_faults_node_auth_from_topology(node):
|
||||
# type: (topology.OpenStackTopologyNode) -> typing.Dict
|
||||
private_key_file = get_os_faults_private_key_file(
|
||||
key_filename=node.ssh_parameters['key_filename'])
|
||||
port = int(node.ssh_parameters.get('port') or 22)
|
||||
if port != 22:
|
||||
LOG.warning('os-faults only support SSH port 22, but requiring %d for '
|
||||
'node %r (%s)', port, node.name, node.public_ip)
|
||||
auth = {'username': node.ssh_parameters['username'],
|
||||
'private_key_file': private_key_file}
|
||||
jump = get_os_faults_node_auth_jump_from_topology(node)
|
||||
if jump:
|
||||
auth['jump'] = jump
|
||||
return auth
|
||||
|
||||
|
||||
def get_os_faults_node_auth_jump_from_topology(node):
|
||||
# type: (topology.OpenStackTopologyNode) -> typing.Optional[typing.Dict]
|
||||
host_config = ssh.ssh_host_config(str(node.public_ip))
|
||||
if host_config.proxy_jump:
|
||||
proxy_config = ssh.ssh_host_config(host_config.proxy_jump)
|
||||
port = int(proxy_config.port or 22)
|
||||
if port != 22:
|
||||
LOG.warning('os-faults only support SSH port 22, but requiring %d '
|
||||
'for proxy %r (%s)', port, host_config.proxy_jump,
|
||||
proxy_config.hostname)
|
||||
private_key_file = get_os_faults_private_key_file(
|
||||
key_filename=proxy_config.key_filename)
|
||||
return {'host': proxy_config.hostname,
|
||||
'username': proxy_config.username,
|
||||
'private_key_file': private_key_file}
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def get_os_faults_private_key_file(key_filename):
|
||||
# type: (typing.Union[str, typing.Sequence]) -> str
|
||||
|
||||
if isinstance(key_filename, six.string_types):
|
||||
key_filename = [key_filename]
|
||||
else:
|
||||
key_filename = list(key_filename)
|
||||
for filename in key_filename:
|
||||
filename = os.path.expanduser(filename)
|
||||
if os.path.exists(filename):
|
||||
return os.path.expanduser(filename)
|
||||
else:
|
||||
LOG.warning('Private key file not found: %r', filename)
|
||||
raise _exception.NoSuchPrivateKeyFilename(
|
||||
key_filename=', '.join(key_filename))
|
||||
|
||||
|
||||
def parse_config_node(node):
|
||||
# type: (str) -> typing.Dict
|
||||
fields = node.split('.')
|
||||
if len(fields) != 2:
|
||||
message = ("Invalid cloud node format: {!r} "
|
||||
"(expected '<name>:<address>')").format(node)
|
||||
raise ValueError(message)
|
||||
return {'name': fields[0], 'address': fields[1]}
|
@ -1,20 +0,0 @@
|
||||
# Copyright 2019 Red Hat
|
||||
#
|
||||
# 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.
|
||||
from __future__ import absolute_import
|
||||
|
||||
import tobiko
|
||||
|
||||
|
||||
class NoSuchPrivateKeyFilename(tobiko.TobikoException):
|
||||
message = "No such private key filename(s): {key_filename}'"
|
@ -1,33 +0,0 @@
|
||||
# Copyright 2019 Red Hat
|
||||
#
|
||||
# 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.
|
||||
from __future__ import absolute_import
|
||||
|
||||
from oslo_log import log
|
||||
import os_faults
|
||||
|
||||
from tobiko.openstack.os_faults import _cloud
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
def os_faults_execute(command, cloud_management=None, config_filename=None,
|
||||
**kwargs):
|
||||
cloud_management = (
|
||||
cloud_management or
|
||||
_cloud.get_os_fault_cloud_managenemt(
|
||||
config_filename=config_filename))
|
||||
if kwargs:
|
||||
command = command.format(**kwargs)
|
||||
return os_faults.human_api(cloud_management, command)
|
@ -1,78 +0,0 @@
|
||||
# Copyright 2019 Red Hat
|
||||
#
|
||||
# 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.
|
||||
from __future__ import absolute_import
|
||||
|
||||
import os
|
||||
import itertools
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
|
||||
OS_FAULTS_SERVICES = ['openvswitch',
|
||||
'tripleo_cinder_api',
|
||||
'tripleo_cinder_api_cron',
|
||||
'tripleo_cinder_scheduler',
|
||||
'tripleo_clustercheck',
|
||||
'tripleo_glance_api',
|
||||
'tripleo_horizon']
|
||||
|
||||
OS_FAULTS_CONTAINERS = ['neutron_ovs_agent',
|
||||
'neutron_metadata_agent',
|
||||
'neutron_api']
|
||||
|
||||
OS_FAULTS_CONFIG_DIRNAMES = ['.',
|
||||
'~/.config/os-faults',
|
||||
'/etc/openstack']
|
||||
|
||||
OS_FAULTS_CONFIG_FILENAMES = ['os-faults.json',
|
||||
'os-faults.yaml',
|
||||
'os-faults.yml']
|
||||
|
||||
OS_FAULTS_TEMPLATE_DIRNAMES = ['.',
|
||||
os.path.join(os.path.dirname(__file__),
|
||||
'templates')]
|
||||
|
||||
OS_FAULTS_GENERATE_CONFIG_DIRNAME = '~/.tobiko/os-faults'
|
||||
|
||||
|
||||
GROUP_NAME = 'os_faults'
|
||||
OPTIONS = [
|
||||
cfg.ListOpt('config_dirnames',
|
||||
default=OS_FAULTS_CONFIG_DIRNAMES,
|
||||
help="Directories where to look for os-faults config file"),
|
||||
cfg.ListOpt('config_filenames',
|
||||
default=OS_FAULTS_CONFIG_FILENAMES,
|
||||
help="Base file names used to look for os-faults config file"),
|
||||
cfg.ListOpt('template_dirnames',
|
||||
default=OS_FAULTS_TEMPLATE_DIRNAMES,
|
||||
help=("location where to look for a template file to be used "
|
||||
"to generate os-faults config file")),
|
||||
cfg.StrOpt('generate_config_dirname',
|
||||
default=OS_FAULTS_GENERATE_CONFIG_DIRNAME,
|
||||
help=("location where to generate config file from template")),
|
||||
cfg.ListOpt('services',
|
||||
default=OS_FAULTS_SERVICES,
|
||||
help="List of services to be handler with os-faults"),
|
||||
cfg.ListOpt('containers',
|
||||
default=OS_FAULTS_CONTAINERS,
|
||||
help="List of containers to be handler with os-faults"),
|
||||
]
|
||||
|
||||
|
||||
def register_tobiko_options(conf):
|
||||
conf.register_opts(group=cfg.OptGroup(GROUP_NAME), opts=OPTIONS)
|
||||
|
||||
|
||||
def list_options():
|
||||
return [(GROUP_NAME, itertools.chain(OPTIONS))]
|
@ -1,40 +0,0 @@
|
||||
cloud_management:
|
||||
driver: universal
|
||||
|
||||
node_discover:
|
||||
driver: node_list
|
||||
args:
|
||||
{% for node in nodes %}
|
||||
- fqdn: {{ node['fqdn'] }}
|
||||
ip: {{ node['ip'] }}
|
||||
auth:
|
||||
username: {{ node['auth']['username'] }}
|
||||
private_key_file: {{ node['auth']['private_key_file'] }}
|
||||
{% if 'jump' in node['auth'] %}
|
||||
jump:
|
||||
host: {{ node['auth']['jump']['host'] }}
|
||||
username: {{ node['auth']['jump']['username'] }}
|
||||
private_key_file: {{ node['auth']['jump']['private_key_file'] }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if services %}
|
||||
services:
|
||||
{% for service in services %}
|
||||
{{ service }}:
|
||||
driver: system_service
|
||||
args:
|
||||
service_name: {{ service }}
|
||||
grep: {{ service }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if containers %}
|
||||
containers:
|
||||
{% for container in containers %}
|
||||
{{ container }}:
|
||||
driver: docker_container
|
||||
args:
|
||||
container_name: {{ container }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
@ -1,26 +0,0 @@
|
||||
# Copyright (c) 2019 Red Hat
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
||||
import testtools
|
||||
from tobiko.openstack import os_faults
|
||||
|
||||
|
||||
class OsFaultsTest(testtools.TestCase):
|
||||
|
||||
def test_nodes_connection(self):
|
||||
cloud_management = os_faults.get_os_fault_cloud_managenemt()
|
||||
cloud_management.verify()
|
@ -1,2 +0,0 @@
|
||||
- name: 'Restart OVS'
|
||||
action: 'restart openvswitch service'
|
@ -1,48 +0,0 @@
|
||||
# Copyright (c) 2018 Red Hat
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
from __future__ import absolute_import
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
from tobiko.cmd import fault as _fault
|
||||
from tobiko.tests import unit
|
||||
|
||||
|
||||
class FaultCMDTest(unit.TobikoUnitTest):
|
||||
|
||||
command_name = 'tobiko-fault'
|
||||
command_class = _fault.FaultCMD
|
||||
default_fault = ["some_fault"]
|
||||
|
||||
def setUp(self):
|
||||
super(FaultCMDTest, self).setUp()
|
||||
self.mock_error = self.patch(argparse.ArgumentParser, 'error',
|
||||
side_effect=self.fail)
|
||||
|
||||
def patch_argv(self, arguments=None):
|
||||
"""Patch argv"""
|
||||
arguments = list(arguments or [])
|
||||
if not arguments:
|
||||
arguments = self.default_fault
|
||||
return self.patch(sys, 'argv',
|
||||
[self.command_name] + arguments)
|
||||
|
||||
def test_init(self, arguments=None):
|
||||
self.patch_argv(arguments=arguments)
|
||||
command = self.command_class()
|
||||
self.mock_error.assert_not_called()
|
||||
args = command.args
|
||||
self.assertIsNotNone(args)
|
Loading…
Reference in New Issue
Block a user