Summary: update host command to use ansible-friendly inventory persistance
Description: - use new jsonpickle storage for hosts/inventory data instead of yaml. this is done to make it easier to store and load the object model for the inventory. - rename hosts class to inventory - remove host-zone association, new association is with groups. This better matches the ansible model. - populate blank inventory with structure required for openstack. This adds the various services and containers under the appropriate groups. - created new group class and updated inventory and host classes. added attributes for host for hypervisor, and management attribute. Also added versions to the inventory class.
This commit is contained in:
parent
a3ce5c852e
commit
1e33dc3d40
315
kollacli/ansible/inventory.py
Normal file
315
kollacli/ansible/inventory.py
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
# Copyright(c) 2015, Oracle and/or its affiliates. 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.
|
||||||
|
import jsonpickle
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
from tempfile import mkstemp
|
||||||
|
|
||||||
|
from kollacli import exceptions
|
||||||
|
from kollacli import utils
|
||||||
|
|
||||||
|
from kollacli.sshutils import ssh_check_host
|
||||||
|
from kollacli.sshutils import ssh_check_keys
|
||||||
|
from kollacli.sshutils import ssh_install_host
|
||||||
|
from kollacli.sshutils import ssh_keygen
|
||||||
|
from kollacli.sshutils import ssh_uninstall_host
|
||||||
|
|
||||||
|
from kollacli.exceptions import CommandError
|
||||||
|
|
||||||
|
INVENTORY_PATH = 'ansible/inventory/inventory.p'
|
||||||
|
|
||||||
|
COMPUTE_GRP_NAME = 'compute'
|
||||||
|
CONTROL_GRP_NAME = 'control'
|
||||||
|
NETWORK_GRP_NAME = 'network'
|
||||||
|
|
||||||
|
DEPLOY_GROUPS = [COMPUTE_GRP_NAME,
|
||||||
|
CONTROL_GRP_NAME,
|
||||||
|
NETWORK_GRP_NAME,
|
||||||
|
]
|
||||||
|
|
||||||
|
SERVICE_GROUPS = ['mariadb', 'rabbitmq', 'keystone', 'glance',
|
||||||
|
'nova', 'haproxy', 'neutron']
|
||||||
|
|
||||||
|
CONTAINER_GROUPS = ['glance-api', 'glance-registry',
|
||||||
|
'nova-api', 'nova-conductor', 'nova-consoleauth',
|
||||||
|
'nova-novncproxy', 'nova-scheduler',
|
||||||
|
'neutron-server', 'neutron-agents']
|
||||||
|
|
||||||
|
DEFAULT_HIERARCHY = {
|
||||||
|
CONTROL_GRP_NAME: {
|
||||||
|
'glance': ['glance-api', 'glance-registry'],
|
||||||
|
'keystone': [],
|
||||||
|
'mariadb': [],
|
||||||
|
'nova': ['nova-api', 'nova-conductor', 'nova-consoleauth',
|
||||||
|
'nova-novncproxy', 'nova-scheduler'],
|
||||||
|
'rabbitmq': [],
|
||||||
|
},
|
||||||
|
NETWORK_GRP_NAME: {
|
||||||
|
'haproxy': [],
|
||||||
|
'neutron': ['neutron-server', 'neutron-agents'],
|
||||||
|
},
|
||||||
|
COMPUTE_GRP_NAME: {
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Host(object):
|
||||||
|
class_version = 1
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def __init__(self, hostname):
|
||||||
|
self.name = hostname
|
||||||
|
self._groups = {} # kv = groupname:group
|
||||||
|
self.alias = ''
|
||||||
|
self.is_mgmt = False
|
||||||
|
self.hypervisor = ''
|
||||||
|
self.vars = {}
|
||||||
|
self.version = self.__class__.class_version
|
||||||
|
|
||||||
|
def upgrade(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _add_group(self, group):
|
||||||
|
if group.name not in self._groups:
|
||||||
|
self._groups[group.name] = group
|
||||||
|
|
||||||
|
def _remove_group(self, group):
|
||||||
|
if group.name in self._groups:
|
||||||
|
del self._groups[group.name]
|
||||||
|
|
||||||
|
def get_groups(self):
|
||||||
|
return self._groups.values()
|
||||||
|
|
||||||
|
def check(self):
|
||||||
|
sshKeysExist = ssh_check_keys()
|
||||||
|
if not sshKeysExist:
|
||||||
|
try:
|
||||||
|
ssh_keygen()
|
||||||
|
except Exception as e:
|
||||||
|
raise exceptions.CommandError(
|
||||||
|
'ERROR: ssh key generation failed on local host : %s'
|
||||||
|
% str(e))
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.log.info('Starting check of host (%s)' % self.name)
|
||||||
|
ssh_check_host(self.name)
|
||||||
|
self.log.info('Host (%s), check succeeded' % self.name)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
raise Exception(
|
||||||
|
'ERROR: Host (%s), check failed. Reason : %s'
|
||||||
|
% (self.name, str(e)))
|
||||||
|
return True
|
||||||
|
|
||||||
|
def install(self, password):
|
||||||
|
self._setup_keys()
|
||||||
|
|
||||||
|
# check if already installed
|
||||||
|
if self._is_installed():
|
||||||
|
self.log.info('Install skipped for host (%s), ' % self.name +
|
||||||
|
'kolla already installed')
|
||||||
|
return True
|
||||||
|
|
||||||
|
# not installed- we need to set up the user / remote ssh keys
|
||||||
|
# using root and the available password
|
||||||
|
try:
|
||||||
|
self.log.info('Starting install of host (%s)'
|
||||||
|
% self.name)
|
||||||
|
ssh_install_host(self.name, password)
|
||||||
|
self.log.info('Host (%s) install succeeded' % self.name)
|
||||||
|
except Exception as e:
|
||||||
|
raise exceptions.CommandError(
|
||||||
|
'ERROR: Host (%s) install failed : %s'
|
||||||
|
% (self.name, str(e)))
|
||||||
|
return True
|
||||||
|
|
||||||
|
def uninstall(self, password):
|
||||||
|
self._setup_keys()
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.log.info('Starting uninstall of host (%s)' % self.name)
|
||||||
|
ssh_uninstall_host(self.name, password)
|
||||||
|
self.log.info('Host (%s) uninstall succeeded' % self.name)
|
||||||
|
except Exception as e:
|
||||||
|
raise exceptions.CommandError(
|
||||||
|
'ERROR: Host (%s) uninstall failed : %s'
|
||||||
|
% (self.name, str(e)))
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _setup_keys(self):
|
||||||
|
sshKeysExist = ssh_check_keys()
|
||||||
|
if not sshKeysExist:
|
||||||
|
try:
|
||||||
|
ssh_keygen()
|
||||||
|
except Exception as e:
|
||||||
|
raise exceptions.CommandError(
|
||||||
|
'ERROR: Error generating ssh keys on local host : %s'
|
||||||
|
% str(e))
|
||||||
|
|
||||||
|
def _is_installed(self):
|
||||||
|
is_installed = False
|
||||||
|
try:
|
||||||
|
ssh_check_host(self.name)
|
||||||
|
is_installed = True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.log.debug('%s' % str(e))
|
||||||
|
pass
|
||||||
|
return is_installed
|
||||||
|
|
||||||
|
|
||||||
|
class Group(object):
|
||||||
|
class_version = 1
|
||||||
|
|
||||||
|
def __init__(self, name):
|
||||||
|
self.name = name
|
||||||
|
self.parent = None
|
||||||
|
self.children = []
|
||||||
|
self._hosts = {} # kv = hostname:object
|
||||||
|
self._version = 1
|
||||||
|
self.vars = {}
|
||||||
|
self.version = self.__class__.class_version
|
||||||
|
|
||||||
|
def upgrade(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def add_host(self, host):
|
||||||
|
if host.name not in self._hosts:
|
||||||
|
self._hosts[host.name] = host
|
||||||
|
else:
|
||||||
|
host = self._hosts[host.name]
|
||||||
|
host._add_group(self)
|
||||||
|
|
||||||
|
def remove_host(self, host):
|
||||||
|
if host.name in self._hosts:
|
||||||
|
host._remove_group(self)
|
||||||
|
del self._hosts[host.name]
|
||||||
|
|
||||||
|
def get_hosts(self):
|
||||||
|
return self._hosts.values()
|
||||||
|
|
||||||
|
|
||||||
|
class Inventory(object):
|
||||||
|
class_version = 1
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._groups = {} # kv = name:object
|
||||||
|
self._hosts = {} # kv = name:object
|
||||||
|
self.vars = {}
|
||||||
|
self.version = self.__class__.class_version
|
||||||
|
|
||||||
|
# initialize the inventory to its defaults
|
||||||
|
self._create_default_inventory()
|
||||||
|
|
||||||
|
def upgrade(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def load():
|
||||||
|
"""load the inventory from a pickle file"""
|
||||||
|
inventory_path = os.path.join(utils.get_client_etc(), INVENTORY_PATH)
|
||||||
|
try:
|
||||||
|
if os.path.exists(inventory_path):
|
||||||
|
with open(inventory_path, 'rb') as inv_file:
|
||||||
|
data = inv_file.read()
|
||||||
|
|
||||||
|
inventory = jsonpickle.decode(data)
|
||||||
|
|
||||||
|
# upgrade version handling
|
||||||
|
if inventory.version != inventory.class_version:
|
||||||
|
inventory.upgrade()
|
||||||
|
else:
|
||||||
|
inventory = Inventory()
|
||||||
|
except Exception as e:
|
||||||
|
raise Exception('ERROR: loading inventory : %s' % str(e))
|
||||||
|
return inventory
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def save(inventory):
|
||||||
|
"""Save the inventory in a pickle file"""
|
||||||
|
inventory_path = os.path.join(utils.get_client_etc(), INVENTORY_PATH)
|
||||||
|
try:
|
||||||
|
# the file handle returned from mkstemp must be closed or else
|
||||||
|
# if this is called many times you will have an unpleasant
|
||||||
|
# file handle leak
|
||||||
|
tmp_filehandle, tmp_path = mkstemp()
|
||||||
|
data = jsonpickle.encode(inventory)
|
||||||
|
with open(tmp_path, 'w') as tmp_file:
|
||||||
|
tmp_file.write(data)
|
||||||
|
shutil.copyfile(tmp_path, inventory_path)
|
||||||
|
os.remove(tmp_path)
|
||||||
|
except Exception as e:
|
||||||
|
raise Exception('ERROR: saving inventory : %s' % str(e))
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
os.close(tmp_filehandle)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if tmp_filehandle is not None:
|
||||||
|
try:
|
||||||
|
os.close(tmp_filehandle)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _create_default_inventory(self):
|
||||||
|
for (deploy_name, services) in DEFAULT_HIERARCHY.items():
|
||||||
|
deploy_group = Group(deploy_name)
|
||||||
|
# add service groups
|
||||||
|
for (service_name, container_names) in services.items():
|
||||||
|
service_group = Group(service_name)
|
||||||
|
deploy_group.children.append(service_group)
|
||||||
|
service_group.parent = deploy_group
|
||||||
|
for container_name in container_names:
|
||||||
|
container_group = Group(container_name)
|
||||||
|
service_group.children.append(container_group)
|
||||||
|
container_group.parent = service_group
|
||||||
|
self._groups[deploy_name] = deploy_group
|
||||||
|
|
||||||
|
def get_hosts(self):
|
||||||
|
return self._hosts.values()
|
||||||
|
|
||||||
|
def get_host(self, hostname):
|
||||||
|
host = None
|
||||||
|
if hostname in self._hosts:
|
||||||
|
host = self._hosts[hostname]
|
||||||
|
return host
|
||||||
|
|
||||||
|
def add_host(self, hostname, groupname):
|
||||||
|
if groupname not in self._groups:
|
||||||
|
raise CommandError('Group name not valid')
|
||||||
|
|
||||||
|
# create new host if it doesn't exist
|
||||||
|
if hostname not in self._hosts:
|
||||||
|
host = Host(hostname)
|
||||||
|
self._hosts[hostname] = host
|
||||||
|
else:
|
||||||
|
host = self._hosts[hostname]
|
||||||
|
|
||||||
|
group = self._groups[groupname]
|
||||||
|
group.add_host(host)
|
||||||
|
|
||||||
|
def remove_host(self, hostname, groupname=None):
|
||||||
|
if hostname in self._hosts:
|
||||||
|
host = self._hosts[hostname]
|
||||||
|
groups = host.get_groups()
|
||||||
|
for group in groups:
|
||||||
|
if not groupname or groupname == group.name:
|
||||||
|
host._remove_group(group)
|
||||||
|
|
||||||
|
# if host no longer exists in any group, remove it from inventory
|
||||||
|
if not host.get_groups():
|
||||||
|
del self._hosts[hostname]
|
@ -17,8 +17,7 @@ import logging
|
|||||||
|
|
||||||
from kollacli import exceptions
|
from kollacli import exceptions
|
||||||
from kollacli.i18n import _
|
from kollacli.i18n import _
|
||||||
from kollacli.objects.hosts import Host
|
from kollacli.ansible.inventory import Inventory
|
||||||
from kollacli.objects.hosts import Hosts
|
|
||||||
from kollacli.objects.zones import Zones
|
from kollacli.objects.zones import Zones
|
||||||
|
|
||||||
from cliff.command import Command
|
from cliff.command import Command
|
||||||
@ -38,45 +37,50 @@ def _zone_not_found(log, zonename):
|
|||||||
|
|
||||||
|
|
||||||
class HostAdd(Command):
|
class HostAdd(Command):
|
||||||
"""Add host to open-stack-kolla
|
"""Add host to open-stack-kolla"""
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
If host already exists, just update the network address.
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(HostAdd, self).get_parser(prog_name)
|
||||||
|
parser.add_argument('hostname', metavar='<hostname>',
|
||||||
|
help='host name or ip address')
|
||||||
|
parser.add_argument('groupname', metavar='<groupname>',
|
||||||
|
help='group name')
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
hostname = parsed_args.hostname.strip()
|
||||||
|
groupname = parsed_args.groupname.strip()
|
||||||
|
|
||||||
|
inventory = Inventory.load()
|
||||||
|
inventory.add_host(hostname, groupname)
|
||||||
|
Inventory.save(inventory)
|
||||||
|
|
||||||
|
|
||||||
|
class HostRemove(Command):
|
||||||
|
"""Remove host from openstack-kolla
|
||||||
|
|
||||||
|
If a group is specified, the host will be removed from that group.
|
||||||
|
If no group is specified, the host will be removed from all groups.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
def get_parser(self, prog_name):
|
|
||||||
parser = super(HostAdd, self).get_parser(prog_name)
|
|
||||||
parser.add_argument('hostname', metavar='<hostname>', help='hostname')
|
|
||||||
parser.add_argument('networkaddress', metavar='networkaddress',
|
|
||||||
help='Network address')
|
|
||||||
return parser
|
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
|
||||||
hostname = parsed_args.hostname.strip()
|
|
||||||
net_addr = parsed_args.networkaddress.strip()
|
|
||||||
|
|
||||||
hosts = Hosts()
|
|
||||||
host = Host(hostname, net_addr)
|
|
||||||
hosts.add_host(host)
|
|
||||||
hosts.save()
|
|
||||||
|
|
||||||
|
|
||||||
class HostRemove(Command):
|
|
||||||
"""Remove host from openstack-kolla"""
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super(HostRemove, self).get_parser(prog_name)
|
parser = super(HostRemove, self).get_parser(prog_name)
|
||||||
parser.add_argument('hostname', metavar='<hostname>', help='hostname')
|
parser.add_argument('hostname', metavar='<hostname>', help='host name')
|
||||||
|
parser.add_argument('groupname', nargs='?',
|
||||||
|
metavar='<group>', help='group name')
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
hostname = parsed_args.hostname.strip()
|
hostname = parsed_args.hostname.strip()
|
||||||
hosts = Hosts()
|
groupname = None
|
||||||
hosts.remove_host(hostname)
|
if parsed_args.groupname:
|
||||||
hosts.save()
|
groupname = parsed_args.groupname.strip()
|
||||||
|
inventory = Inventory.load()
|
||||||
|
inventory.remove_host(hostname, groupname)
|
||||||
|
Inventory.save(inventory)
|
||||||
|
|
||||||
|
|
||||||
class HostList(Lister):
|
class HostList(Lister):
|
||||||
@ -85,14 +89,19 @@ class HostList(Lister):
|
|||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
hosts = Hosts().get_all()
|
inventory = Inventory.load()
|
||||||
|
|
||||||
|
hosts = inventory.get_hosts()
|
||||||
data = []
|
data = []
|
||||||
if hosts:
|
if hosts:
|
||||||
for host in hosts:
|
for host in hosts:
|
||||||
data.append((host.hostname, host.net_addr, host.zone))
|
groupnames = []
|
||||||
|
for group in host.get_groups():
|
||||||
|
groupnames.append(group.name)
|
||||||
|
data.append((host.name, groupnames))
|
||||||
else:
|
else:
|
||||||
data.append(('', '', ''))
|
data.append(('', ''))
|
||||||
return (('Host Name', 'Address', 'Zone'), data)
|
return (('Host Name', 'Groups'), data)
|
||||||
|
|
||||||
|
|
||||||
class HostSetzone(Command):
|
class HostSetzone(Command):
|
||||||
@ -114,7 +123,7 @@ class HostSetzone(Command):
|
|||||||
_zone_not_found(self.log, zonename)
|
_zone_not_found(self.log, zonename)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
hosts = Hosts()
|
hosts = Inventory()
|
||||||
host = hosts.get_host(hostname)
|
host = hosts.get_host(hostname)
|
||||||
if not host:
|
if not host:
|
||||||
_host_not_found(self.log, hostname)
|
_host_not_found(self.log, hostname)
|
||||||
@ -137,7 +146,7 @@ class HostClearzone(Command):
|
|||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
hostname = parsed_args.hostname.strip()
|
hostname = parsed_args.hostname.strip()
|
||||||
|
|
||||||
hosts = Hosts()
|
hosts = Inventory()
|
||||||
host = hosts.get_host(hostname)
|
host = hosts.get_host(hostname)
|
||||||
if not host:
|
if not host:
|
||||||
_host_not_found(self.log, hostname)
|
_host_not_found(self.log, hostname)
|
||||||
@ -180,7 +189,8 @@ class HostCheck(Command):
|
|||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
hostname = parsed_args.hostname.strip()
|
hostname = parsed_args.hostname.strip()
|
||||||
|
|
||||||
host = Hosts().get_host(hostname)
|
inventory = Inventory.load()
|
||||||
|
host = inventory.get_host(hostname)
|
||||||
if not host:
|
if not host:
|
||||||
_host_not_found(self.log, hostname)
|
_host_not_found(self.log, hostname)
|
||||||
return False
|
return False
|
||||||
@ -201,7 +211,8 @@ class HostInstall(Command):
|
|||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
hostname = parsed_args.hostname.strip()
|
hostname = parsed_args.hostname.strip()
|
||||||
host = Hosts().get_host(hostname)
|
inventory = Inventory.load()
|
||||||
|
host = inventory.get_host(hostname)
|
||||||
if not host:
|
if not host:
|
||||||
_host_not_found(self.log, hostname)
|
_host_not_found(self.log, hostname)
|
||||||
return False
|
return False
|
||||||
@ -227,7 +238,8 @@ class HostUninstall(Command):
|
|||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
hostname = parsed_args.hostname.strip()
|
hostname = parsed_args.hostname.strip()
|
||||||
host = Hosts().get_host(hostname)
|
inventory = Inventory.load()
|
||||||
|
host = inventory.get_host(hostname)
|
||||||
if not host:
|
if not host:
|
||||||
_host_not_found(self.log, hostname)
|
_host_not_found(self.log, hostname)
|
||||||
return False
|
return False
|
||||||
|
@ -1,166 +0,0 @@
|
|||||||
# Copyright(c) 2015, Oracle and/or its affiliates. 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.
|
|
||||||
import logging
|
|
||||||
|
|
||||||
from kollacli import exceptions
|
|
||||||
from kollacli import utils
|
|
||||||
|
|
||||||
from kollacli.sshutils import ssh_check_host
|
|
||||||
from kollacli.sshutils import ssh_check_keys
|
|
||||||
from kollacli.sshutils import ssh_install_host
|
|
||||||
from kollacli.sshutils import ssh_keygen
|
|
||||||
from kollacli.sshutils import ssh_uninstall_host
|
|
||||||
|
|
||||||
|
|
||||||
class Host(object):
|
|
||||||
hostname = ''
|
|
||||||
net_addr = ''
|
|
||||||
zone = ''
|
|
||||||
services = []
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
def __init__(self, hostname, net_addr=''):
|
|
||||||
self.hostname = hostname
|
|
||||||
self.net_addr = net_addr
|
|
||||||
|
|
||||||
def check(self):
|
|
||||||
sshKeysExist = ssh_check_keys()
|
|
||||||
if not sshKeysExist:
|
|
||||||
try:
|
|
||||||
ssh_keygen()
|
|
||||||
except Exception as e:
|
|
||||||
raise exceptions.CommandError(
|
|
||||||
'ERROR: ssh key generation failed on local host : %s'
|
|
||||||
% str(e))
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.log.info('Starting host (%s) check at address (%s)' %
|
|
||||||
(self.hostname, self.net_addr))
|
|
||||||
ssh_check_host(self.net_addr)
|
|
||||||
self.log.info('Host (%s), check succeeded' % self.hostname)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
raise Exception(
|
|
||||||
'ERROR: Host (%s), check failed. Reason : %s'
|
|
||||||
% (self.hostname, str(e)))
|
|
||||||
return True
|
|
||||||
|
|
||||||
def install(self, password):
|
|
||||||
self._setup_keys()
|
|
||||||
|
|
||||||
# check if already installed
|
|
||||||
if self._is_installed():
|
|
||||||
self.log.info('Install skipped for host (%s), ' % self.hostname +
|
|
||||||
'kolla already installed')
|
|
||||||
return True
|
|
||||||
|
|
||||||
# not installed- we need to set up the user / remote ssh keys
|
|
||||||
# using root and the available password
|
|
||||||
try:
|
|
||||||
self.log.info('Starting install of host (%s) at address (%s)'
|
|
||||||
% (self.hostname, self.net_addr))
|
|
||||||
ssh_install_host(self.net_addr, password)
|
|
||||||
self.log.info('Host (%s) install succeeded' % self.hostname)
|
|
||||||
except Exception as e:
|
|
||||||
raise exceptions.CommandError(
|
|
||||||
'ERROR: Host (%s) install failed : %s'
|
|
||||||
% (self.hostname, str(e)))
|
|
||||||
return True
|
|
||||||
|
|
||||||
def uninstall(self, password):
|
|
||||||
self._setup_keys()
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.log.info('Starting uninstall of host (%s) at address (%s)'
|
|
||||||
% (self.hostname, self.net_addr))
|
|
||||||
ssh_uninstall_host(self.net_addr, password)
|
|
||||||
self.log.info('Host (%s) uninstall succeeded' % self.hostname)
|
|
||||||
except Exception as e:
|
|
||||||
raise exceptions.CommandError(
|
|
||||||
'ERROR: Host (%s) uninstall failed : %s'
|
|
||||||
% (self.hostname, str(e)))
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _setup_keys(self):
|
|
||||||
sshKeysExist = ssh_check_keys()
|
|
||||||
if not sshKeysExist:
|
|
||||||
try:
|
|
||||||
ssh_keygen()
|
|
||||||
except Exception as e:
|
|
||||||
raise exceptions.CommandError(
|
|
||||||
'ERROR: Error generating ssh keys on local host : %s'
|
|
||||||
% str(e))
|
|
||||||
|
|
||||||
def _is_installed(self):
|
|
||||||
is_installed = False
|
|
||||||
try:
|
|
||||||
ssh_check_host(self.net_addr)
|
|
||||||
is_installed = True
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
self.log.debug('%s' % str(e))
|
|
||||||
pass
|
|
||||||
return is_installed
|
|
||||||
|
|
||||||
|
|
||||||
class Hosts(object):
|
|
||||||
_hosts = {}
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
yml = utils.load_etc_yaml('hosts.yml')
|
|
||||||
for (hostname, info) in yml.items():
|
|
||||||
host = Host(hostname)
|
|
||||||
if 'NetworkAddress' in info:
|
|
||||||
host.net_addr = info['NetworkAddress']
|
|
||||||
if 'Zone' in info:
|
|
||||||
host.zone = info['Zone']
|
|
||||||
if 'Services' in info:
|
|
||||||
service_list = info['Services']
|
|
||||||
if service_list:
|
|
||||||
host.services = service_list.split(',')
|
|
||||||
self._hosts[hostname] = host
|
|
||||||
|
|
||||||
def get_all(self):
|
|
||||||
return self._hosts.values()
|
|
||||||
|
|
||||||
def get_host(self, hostname):
|
|
||||||
host = None
|
|
||||||
if hostname in self._hosts:
|
|
||||||
host = self._hosts[hostname]
|
|
||||||
return host
|
|
||||||
|
|
||||||
def add_host(self, host):
|
|
||||||
if host.hostname not in self._hosts:
|
|
||||||
self._hosts[host.hostname] = host
|
|
||||||
else:
|
|
||||||
# existing host, just update network address
|
|
||||||
cur_host = self._hosts[host.hostname]
|
|
||||||
cur_host.net_addr = host.net_addr
|
|
||||||
|
|
||||||
def remove_host(self, hostname):
|
|
||||||
if hostname in self._hosts:
|
|
||||||
del self._hosts[hostname]
|
|
||||||
|
|
||||||
def save(self):
|
|
||||||
"""save hosts info"""
|
|
||||||
info = {}
|
|
||||||
for host in self._hosts.values():
|
|
||||||
info[host.hostname] = {}
|
|
||||||
info[host.hostname]['NetworkAddress'] = host.net_addr
|
|
||||||
info[host.hostname]['Zone'] = host.zone
|
|
||||||
info[host.hostname]['Services'] = []
|
|
||||||
for service in host.services:
|
|
||||||
info[host.hostname]['Services'].append(service)
|
|
||||||
|
|
||||||
utils.save_etc_yaml('hosts.yml', info)
|
|
@ -2,6 +2,7 @@ Babel>=1.3
|
|||||||
cliff>=1.10.0 # Apache-2.0
|
cliff>=1.10.0 # Apache-2.0
|
||||||
cliff-tablib>=1.1
|
cliff-tablib>=1.1
|
||||||
docker-py>=1.3
|
docker-py>=1.3
|
||||||
|
jsonpickle>=0.9
|
||||||
oslo.i18n>=1.5.0 # Apache-2.0
|
oslo.i18n>=1.5.0 # Apache-2.0
|
||||||
paramiko
|
paramiko
|
||||||
pbr>=0.11,<2.0
|
pbr>=0.11,<2.0
|
||||||
|
161
tests/common.py
161
tests/common.py
@ -22,12 +22,12 @@ import testtools
|
|||||||
|
|
||||||
import kollacli.utils as utils
|
import kollacli.utils as utils
|
||||||
|
|
||||||
|
TEST_SUFFIX = 'test/'
|
||||||
TEST_SUFFIX = '/test/'
|
|
||||||
ENV_ETC = 'KOLLA_CLIENT_ETC'
|
ENV_ETC = 'KOLLA_CLIENT_ETC'
|
||||||
VENV_PY_PATH = '/.venv/bin/python'
|
VENV_PY_PATH = '.venv/bin/python'
|
||||||
KOLLA_CMD = 'kollacli'
|
KOLLA_CMD = 'kollacli'
|
||||||
KOLLA_SHELL_DIR = 'kollacli'
|
KOLLA_SHELL_DIR = 'kollacli'
|
||||||
|
|
||||||
HOSTS_FNAME = 'test_hosts'
|
HOSTS_FNAME = 'test_hosts'
|
||||||
|
|
||||||
|
|
||||||
@ -51,13 +51,13 @@ class KollaCliTest(testtools.TestCase):
|
|||||||
|
|
||||||
self._set_cmd_prefix()
|
self._set_cmd_prefix()
|
||||||
|
|
||||||
# make sure hosts and zones yaml files exist
|
# make sure inventory dirs exists and remove inventory file
|
||||||
# and clear them out
|
|
||||||
self._init_dir(etc_path)
|
self._init_dir(etc_path)
|
||||||
hosts_path = etc_path + '/hosts.yml'
|
etc_ansible_path = os.path.join(etc_path, 'ansible/')
|
||||||
self._init_file(hosts_path)
|
self._init_dir(etc_ansible_path)
|
||||||
zones_path = etc_path + '/zones.yml'
|
etc_inventory_path = os.path.join(etc_ansible_path, 'inventory/')
|
||||||
self._init_file(zones_path)
|
self._init_dir(etc_inventory_path)
|
||||||
|
self._init_file(os.path.join(etc_inventory_path, 'inventory.p'))
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self._restore_env_var()
|
self._restore_env_var()
|
||||||
@ -73,73 +73,12 @@ class KollaCliTest(testtools.TestCase):
|
|||||||
% (msg, full_cmd)))
|
% (msg, full_cmd)))
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
def get_test_hosts(self):
|
|
||||||
"""get hosts from test_hosts file
|
|
||||||
|
|
||||||
host is {hostname: net_addr}
|
|
||||||
"""
|
|
||||||
hosts = None
|
|
||||||
if not os.path.exists(HOSTS_FNAME):
|
|
||||||
self.log.error('test_hosts file not found, are you running' +
|
|
||||||
'the tests in the tests directory?')
|
|
||||||
return hosts
|
|
||||||
with open(HOSTS_FNAME, 'r') as f:
|
|
||||||
hosts = self.TestHosts()
|
|
||||||
for line in f:
|
|
||||||
line = line.strip()
|
|
||||||
if not line or line.startswith('#'):
|
|
||||||
continue
|
|
||||||
|
|
||||||
tokens = line.split()
|
|
||||||
self.assertIs(True, len(tokens) > 2,
|
|
||||||
'%s expected 3 params on line: %s'
|
|
||||||
% (HOSTS_FNAME, line))
|
|
||||||
hostname = tokens[0]
|
|
||||||
net_addr = tokens[1]
|
|
||||||
pwd = tokens[2]
|
|
||||||
hosts.add(hostname, net_addr)
|
|
||||||
hosts.set_password(hostname, pwd)
|
|
||||||
return hosts
|
|
||||||
|
|
||||||
class TestHosts(object):
|
|
||||||
"""test representation of host data"""
|
|
||||||
info = {}
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.info = {}
|
|
||||||
|
|
||||||
def remove(self, name):
|
|
||||||
del self.info[name]
|
|
||||||
|
|
||||||
def add(self, name, ip, zone='', services=[]):
|
|
||||||
if name not in self.info:
|
|
||||||
self.info[name] = {}
|
|
||||||
self.info[name]['net'] = ip
|
|
||||||
self.info[name]['zone'] = zone
|
|
||||||
self.info[name]['services'] = services
|
|
||||||
|
|
||||||
def get_ip(self, name):
|
|
||||||
return self.info[name]['net']
|
|
||||||
|
|
||||||
def get_zone(self, name):
|
|
||||||
return self.info[name]['zone']
|
|
||||||
|
|
||||||
def get_services(self, name):
|
|
||||||
return self.info[name]['services']
|
|
||||||
|
|
||||||
def get_hostnames(self):
|
|
||||||
return self.info.keys()
|
|
||||||
|
|
||||||
def set_password(self, name, password):
|
|
||||||
self.info[name]['pwd'] = password
|
|
||||||
|
|
||||||
def get_password(self, name):
|
|
||||||
return self.info[name]['pwd']
|
|
||||||
|
|
||||||
# PRIVATE FUNCTIONS ----------------------------------------------------
|
# PRIVATE FUNCTIONS ----------------------------------------------------
|
||||||
def _setup_env_var(self):
|
def _setup_env_var(self):
|
||||||
new_etc_path = utils.get_client_etc() + TEST_SUFFIX
|
etc_path = utils.get_client_etc()
|
||||||
os.environ[ENV_ETC] = new_etc_path
|
if not etc_path.endswith(TEST_SUFFIX):
|
||||||
|
etc_path = os.path.join(etc_path, TEST_SUFFIX)
|
||||||
|
os.environ[ENV_ETC] = etc_path
|
||||||
|
|
||||||
def _restore_env_var(self):
|
def _restore_env_var(self):
|
||||||
etc_path = utils.get_client_etc()
|
etc_path = utils.get_client_etc()
|
||||||
@ -170,12 +109,12 @@ class KollaCliTest(testtools.TestCase):
|
|||||||
return (retval, msg)
|
return (retval, msg)
|
||||||
|
|
||||||
def _init_file(self, filepath):
|
def _init_file(self, filepath):
|
||||||
with open(filepath, 'w') as f:
|
if os.path.exists(filepath):
|
||||||
f.close()
|
os.remove(filepath)
|
||||||
|
|
||||||
def _init_dir(self, path):
|
def _init_dir(self, path):
|
||||||
if not os.path.isdir(path):
|
if not os.path.isdir(path):
|
||||||
os.makedirs(path)
|
os.mkdir(path)
|
||||||
|
|
||||||
def _set_cmd_prefix(self):
|
def _set_cmd_prefix(self):
|
||||||
"""Select the command to invoke the kollacli
|
"""Select the command to invoke the kollacli
|
||||||
@ -210,9 +149,9 @@ class KollaCliTest(testtools.TestCase):
|
|||||||
os_kolla_dir = cwd.rsplit('/', 1)[0]
|
os_kolla_dir = cwd.rsplit('/', 1)[0]
|
||||||
|
|
||||||
shell_dir = os_kolla_dir + '/%s/' % KOLLA_SHELL_DIR
|
shell_dir = os_kolla_dir + '/%s/' % KOLLA_SHELL_DIR
|
||||||
shell_path = shell_dir + 'shell.py'
|
shell_path = os.path.join(shell_dir, 'shell.py')
|
||||||
|
|
||||||
python_path = os_kolla_dir + VENV_PY_PATH
|
python_path = os.path.join(os_kolla_dir, VENV_PY_PATH)
|
||||||
|
|
||||||
self.log.debug('shell_path: %s' % shell_path)
|
self.log.debug('shell_path: %s' % shell_path)
|
||||||
self.log.debug('python_path: %s' % python_path)
|
self.log.debug('python_path: %s' % python_path)
|
||||||
@ -225,3 +164,67 @@ class KollaCliTest(testtools.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(0, 1,
|
self.assertEqual(0, 1,
|
||||||
'no kollacli shell command found. Aborting tests')
|
'no kollacli shell command found. Aborting tests')
|
||||||
|
|
||||||
|
|
||||||
|
class TestHosts(object):
|
||||||
|
"""host systems for testing
|
||||||
|
|
||||||
|
This class can either be used for metadata to hold info about test hosts,
|
||||||
|
or can be loaded from a test file for info on actual test host machines.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.info = {}
|
||||||
|
|
||||||
|
def remove(self, name):
|
||||||
|
del self.info[name]
|
||||||
|
|
||||||
|
def add(self, name):
|
||||||
|
if name not in self.info:
|
||||||
|
self.info[name] = {'groups': [],
|
||||||
|
'pwd': '',
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_groups(self, name):
|
||||||
|
return self.info[name]['groups']
|
||||||
|
|
||||||
|
def add_group(self, name, group):
|
||||||
|
if group not in self.info[name]['groups']:
|
||||||
|
self.info[name]['groups'].append(group)
|
||||||
|
|
||||||
|
def remove_group(self, name, group):
|
||||||
|
if group in self.info[name]['groups']:
|
||||||
|
self.info[name]['groups'].remove(group)
|
||||||
|
|
||||||
|
def get_hostnames(self):
|
||||||
|
return self.info.keys()
|
||||||
|
|
||||||
|
def set_password(self, name, password):
|
||||||
|
self.info[name]['pwd'] = password
|
||||||
|
|
||||||
|
def get_password(self, name):
|
||||||
|
return self.info[name]['pwd']
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
"""load hosts from test_hosts file
|
||||||
|
|
||||||
|
"""
|
||||||
|
hosts = None
|
||||||
|
if not os.path.exists(HOSTS_FNAME):
|
||||||
|
self.log.error('test_hosts file not found, are you running ' +
|
||||||
|
'the tests in the tests directory?')
|
||||||
|
return hosts
|
||||||
|
with open(HOSTS_FNAME, 'r') as f:
|
||||||
|
for line in f:
|
||||||
|
line = line.strip()
|
||||||
|
if not line or line.startswith('#'):
|
||||||
|
continue
|
||||||
|
|
||||||
|
tokens = line.split()
|
||||||
|
if len(tokens) != 3:
|
||||||
|
raise Exception('%s expected 3 params on line: %s'
|
||||||
|
% (HOSTS_FNAME, line))
|
||||||
|
hostname = tokens[0]
|
||||||
|
pwd = tokens[2]
|
||||||
|
self.add(hostname)
|
||||||
|
self.set_password(hostname, pwd)
|
||||||
|
183
tests/host.py
183
tests/host.py
@ -13,85 +13,97 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
#
|
#
|
||||||
from common import KollaCliTest
|
from common import KollaCliTest
|
||||||
import unittest
|
from common import TestHosts
|
||||||
|
|
||||||
|
import json
|
||||||
|
import unittest
|
||||||
|
|
||||||
class TestFunctional(KollaCliTest):
|
class TestFunctional(KollaCliTest):
|
||||||
|
|
||||||
def test_host_add_remove(self):
|
def test_host_add_remove(self):
|
||||||
hosts = self.TestHosts()
|
hosts = TestHosts()
|
||||||
|
|
||||||
msg = self.run_client_cmd('host list')
|
msg = self.run_client_cmd('host list -f json')
|
||||||
self._check_cli_output(hosts, msg)
|
self._check_cli_output(hosts, msg)
|
||||||
|
|
||||||
hostname = 'host_test1'
|
host1 = 'host_test1'
|
||||||
ip_addr = '1.1.1.1'
|
host2 = 'host_test2'
|
||||||
hosts.add(hostname, ip_addr)
|
|
||||||
self.run_client_cmd('host add %s %s' % (hostname, ip_addr))
|
|
||||||
|
|
||||||
msg = self.run_client_cmd('host list')
|
group1 = 'control'
|
||||||
|
group2 = 'network'
|
||||||
|
group3 = 'compute'
|
||||||
|
|
||||||
|
hosts.add(host1)
|
||||||
|
hosts.add_group(host1, group1)
|
||||||
|
self.run_client_cmd('host add %s %s' % (host1, group1))
|
||||||
|
msg = self.run_client_cmd('host list -f json')
|
||||||
self._check_cli_output(hosts, msg)
|
self._check_cli_output(hosts, msg)
|
||||||
|
|
||||||
hostname = 'host_test2'
|
hosts.add_group(host1, group2)
|
||||||
ip_addr = '2.2.2.2'
|
self.run_client_cmd('host add %s %s' % (host1, group2))
|
||||||
hosts.add(hostname, ip_addr)
|
msg = self.run_client_cmd('host list -f json')
|
||||||
self.run_client_cmd('host add %s %s' % (hostname, ip_addr))
|
|
||||||
|
|
||||||
msg = self.run_client_cmd('host list')
|
|
||||||
self._check_cli_output(hosts, msg)
|
self._check_cli_output(hosts, msg)
|
||||||
|
|
||||||
hostname = 'host_test2'
|
hosts.remove_group(host1, group1)
|
||||||
hosts.remove(hostname)
|
self.run_client_cmd('host remove %s %s' % (host1, group1))
|
||||||
self.run_client_cmd('host remove %s' % hostname)
|
msg = self.run_client_cmd('host list -f json')
|
||||||
|
|
||||||
msg = self.run_client_cmd('host list')
|
|
||||||
self._check_cli_output(hosts, msg)
|
self._check_cli_output(hosts, msg)
|
||||||
|
|
||||||
hostname = 'host_test1'
|
hosts.add(host2)
|
||||||
hosts.remove(hostname)
|
hosts.add_group(host2, group3)
|
||||||
self.run_client_cmd('host remove %s' % hostname)
|
self.run_client_cmd('host add %s %s' % (host2, group3))
|
||||||
|
msg = self.run_client_cmd('host list -f json')
|
||||||
msg = self.run_client_cmd('host list')
|
|
||||||
self._check_cli_output(hosts, msg)
|
self._check_cli_output(hosts, msg)
|
||||||
|
|
||||||
def test_host_setzone(self):
|
hosts.remove(host2)
|
||||||
hosts = self.TestHosts()
|
self.run_client_cmd('host remove %s %s' % (host2, group3))
|
||||||
hostname = 'host_test1'
|
msg = self.run_client_cmd('host list -f json')
|
||||||
ip_addr = '1.1.1.1'
|
|
||||||
zonename = 'test_zone1'
|
|
||||||
hosts.add(hostname, ip_addr, zonename)
|
|
||||||
self.run_client_cmd('zone add %s' % zonename)
|
|
||||||
|
|
||||||
self.run_client_cmd('host add %s %s' % (hostname, ip_addr))
|
|
||||||
self.run_client_cmd('host setzone %s %s' % (hostname, zonename))
|
|
||||||
msg = self.run_client_cmd('host list')
|
|
||||||
self._check_cli_output(hosts, msg)
|
self._check_cli_output(hosts, msg)
|
||||||
|
|
||||||
zonename = 'test_zone2'
|
hosts.remove(host1)
|
||||||
hosts.add(hostname, ip_addr, zonename)
|
self.run_client_cmd('host remove %s' % host1)
|
||||||
self.run_client_cmd('zone add %s' % zonename)
|
msg = self.run_client_cmd('host list -f json')
|
||||||
|
|
||||||
self.run_client_cmd('host setzone %s %s' % (hostname, zonename))
|
|
||||||
msg = self.run_client_cmd('host list')
|
|
||||||
self._check_cli_output(hosts, msg)
|
self._check_cli_output(hosts, msg)
|
||||||
|
|
||||||
zonename = ''
|
# def test_host_setzone(self):
|
||||||
hosts.add(hostname, ip_addr, zonename)
|
# hosts = self.TestHosts()
|
||||||
self.run_client_cmd('host clearzone %s' % hostname)
|
# hostname = 'host_test1'
|
||||||
msg = self.run_client_cmd('host list')
|
# ip_addr = '1.1.1.1'
|
||||||
self._check_cli_output(hosts, msg)
|
# zonename = 'test_zone1'
|
||||||
|
# hosts.add(hostname, ip_addr, zonename)
|
||||||
|
# self.run_client_cmd('zone add %s' % zonename)
|
||||||
|
#
|
||||||
|
# self.run_client_cmd('host add %s %s' % (hostname, ip_addr))
|
||||||
|
# self.run_client_cmd('host setzone %s %s' % (hostname, zonename))
|
||||||
|
# msg = self.run_client_cmd('host list')
|
||||||
|
# self._check_cli_output(hosts, msg)
|
||||||
|
#
|
||||||
|
# zonename = 'test_zone2'
|
||||||
|
# hosts.add(hostname, ip_addr, zonename)
|
||||||
|
# self.run_client_cmd('zone add %s' % zonename)
|
||||||
|
#
|
||||||
|
# self.run_client_cmd('host setzone %s %s' % (hostname, zonename))
|
||||||
|
# msg = self.run_client_cmd('host list')
|
||||||
|
# self._check_cli_output(hosts, msg)
|
||||||
|
#
|
||||||
|
# zonename = ''
|
||||||
|
# hosts.add(hostname, ip_addr, zonename)
|
||||||
|
# self.run_client_cmd('host clearzone %s' % hostname)
|
||||||
|
# msg = self.run_client_cmd('host list')
|
||||||
|
# self._check_cli_output(hosts, msg)
|
||||||
|
|
||||||
def test_host_install(self):
|
def test_host_install(self):
|
||||||
test_hosts = self.get_test_hosts()
|
test_hosts = TestHosts()
|
||||||
|
test_hosts.load()
|
||||||
|
|
||||||
if not test_hosts:
|
if not test_hosts:
|
||||||
self.log.info('no test_hosts file found, skipping test')
|
self.log.info('no test_hosts file found, skipping test')
|
||||||
return
|
return
|
||||||
|
|
||||||
hostname = test_hosts.get_hostnames()[0]
|
hostname = test_hosts.get_hostnames()[0]
|
||||||
net_addr = test_hosts.get_ip(hostname)
|
|
||||||
pwd = test_hosts.get_password(hostname)
|
pwd = test_hosts.get_password(hostname)
|
||||||
|
|
||||||
self.run_client_cmd('host add %s %s' % (hostname, net_addr))
|
self.run_client_cmd('host add %s control' % (hostname))
|
||||||
|
|
||||||
# check if host is installed
|
# check if host is installed
|
||||||
msg = self.run_client_cmd('host check %s' % hostname, True)
|
msg = self.run_client_cmd('host check %s' % hostname, True)
|
||||||
@ -117,60 +129,45 @@ class TestFunctional(KollaCliTest):
|
|||||||
self.assertIn('ERROR:', msg, 'Uninstall failed on host: (%s)'
|
self.assertIn('ERROR:', msg, 'Uninstall failed on host: (%s)'
|
||||||
% hostname)
|
% hostname)
|
||||||
|
|
||||||
def _check_cli_output(self, hosts, cli_output):
|
def _check_cli_output(self, exp_hosts, cli_output):
|
||||||
"""Verify cli data against model data
|
"""Verify cli data against model data
|
||||||
|
|
||||||
The host list cli output looks like this:
|
The host list cli output looks like this:
|
||||||
|
|
||||||
+-----------+---------+------+
|
$ host list -f json
|
||||||
| Host Name | Address | Zone |
|
[{"Host Name": "foo", "Groups": ["control", "network"]}]
|
||||||
+-----------+---------+------+
|
|
||||||
| foobar | 2.2.2.2 | |
|
|
||||||
| foo | 1.1.1.1 | |
|
|
||||||
+-----------+---------+------+
|
|
||||||
"""
|
"""
|
||||||
# check for any host in cli output that shouldn't be there
|
# check for any host in cli output that shouldn't be there
|
||||||
cli_lines = cli_output.split('\n')
|
cli_hosts = json.loads(cli_output)
|
||||||
exp_hosts = hosts.get_hostnames()
|
|
||||||
for cli_line in cli_lines:
|
exp_hostnames = exp_hosts.get_hostnames()
|
||||||
if ('|' not in cli_line or
|
if not exp_hostnames:
|
||||||
cli_line.startswith('+') or
|
if len(cli_hosts) == 1:
|
||||||
cli_line.startswith('| Host Name ')):
|
cli_hostname = cli_hosts[0]['Host Name']
|
||||||
continue
|
if not cli_hostname:
|
||||||
cli_host = cli_line.split('|')[1].strip()
|
# both cli and expected hosts are None
|
||||||
if cli_host:
|
return
|
||||||
self.assertIn(cli_host, exp_hosts,
|
|
||||||
|
for cli_host in cli_hosts:
|
||||||
|
cli_hostname = cli_host['Host Name']
|
||||||
|
self.assertIn(cli_hostname, exp_hostnames,
|
||||||
'unexpected host: %s, found in cli output: %s'
|
'unexpected host: %s, found in cli output: %s'
|
||||||
% (cli_host, cli_lines))
|
% (cli_hostname, cli_output))
|
||||||
|
|
||||||
for hostname in exp_hosts:
|
# check that all expected hosts are in the output
|
||||||
exp_ip = hosts.get_ip(hostname)
|
for exp_hostname in exp_hosts.get_hostnames():
|
||||||
exp_zone = hosts.get_zone(hostname)
|
exp_host_found = False
|
||||||
|
for cli_host in cli_hosts:
|
||||||
|
if exp_hostname == cli_host['Host Name']:
|
||||||
|
exp_host_found = True
|
||||||
|
cli_groups = cli_host['Groups']
|
||||||
|
exp_groups = exp_hosts.get_groups(exp_hostname)
|
||||||
|
self.assertEqual(exp_groups, cli_groups)
|
||||||
|
|
||||||
hostname_found = False
|
self.assertTrue(exp_host_found,
|
||||||
for cli_line in cli_lines:
|
|
||||||
if ('|' not in cli_line or
|
|
||||||
cli_line.startswith('+') or
|
|
||||||
cli_line.startswith('| Host Name ')):
|
|
||||||
continue
|
|
||||||
|
|
||||||
tokens = cli_line.split('|')
|
|
||||||
if tokens[1].strip() == hostname:
|
|
||||||
hostname_found = True
|
|
||||||
|
|
||||||
# check network address
|
|
||||||
yaml_ip = tokens[2].strip()
|
|
||||||
self.assertEqual(exp_ip, yaml_ip,
|
|
||||||
'incorrect ip address in cli output')
|
|
||||||
|
|
||||||
# check zone
|
|
||||||
yaml_zone = tokens[3].strip()
|
|
||||||
self.assertEqual(exp_zone, yaml_zone,
|
|
||||||
'incorrect zone in cli output')
|
|
||||||
|
|
||||||
self.assertTrue(hostname_found,
|
|
||||||
'hostname: %s not in cli output: \n%s'
|
'hostname: %s not in cli output: \n%s'
|
||||||
% (hostname, cli_output))
|
% (exp_hostname, cli_output))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
Loading…
Reference in New Issue
Block a user