Summary: add 4 new cli group commands

Description:
- new commands:
  - group add / remove
  - group listservices
  - group listhosts
- make jsonpickle output read-able
- add try/excepts in host.py to better debug errors
- remove zones logic
This commit is contained in:
Steve Noyes 2015-08-14 17:33:22 -04:00
parent 226a017887
commit 755cf0f96c
5 changed files with 244 additions and 185 deletions

View File

@ -247,9 +247,13 @@ class Inventory(object):
# if this is called many times you will have an unpleasant
# file handle leak
tmp_filehandle, tmp_path = mkstemp()
# multiple trips thru json to render a readable inventory file
data = jsonpickle.encode(inventory)
data_str = json.loads(data)
pretty_data = json.dumps(data_str, indent=4)
with open(tmp_path, 'w') as tmp_file:
tmp_file.write(data)
tmp_file.write(pretty_data)
shutil.copyfile(tmp_path, inventory_path)
os.remove(tmp_path)
except Exception as e:
@ -284,6 +288,17 @@ class Inventory(object):
def get_hostnames(self):
return self._hosts.keys()
def get_host_groups(self):
"""return { hostname : groupnames }"""
host_groups = {}
for host in self._hosts.values():
host_groups[host.name] = []
groups = self.get_groups(host)
for group in groups:
host_groups[host.name].append(group.name)
return host_groups
def get_host(self, hostname):
host = None
if hostname in self._hosts:
@ -318,6 +333,14 @@ class Inventory(object):
if group_count == 0:
del self._hosts[hostname]
def add_group(self, groupname):
if groupname not in self._groups:
self._groups[groupname] = Group(groupname)
def remove_group(self, groupname):
if groupname in self._groups:
del self._groups[groupname]
def get_groups(self, host=None):
"""return all groups containing host
@ -325,31 +348,30 @@ class Inventory(object):
"""
if not host:
return self._groups.values()
host_groups = self.get_host_groups([host])
groupnames = host_groups[host.name]
groups = []
for groupname in groupnames:
groups.append(self._groups[groupname])
for group in self._groups.values():
if host.name in group.get_hostnames():
groups.append(group)
return groups
def get_host_groups(self, hosts):
"""returns a dict: { hostname : [groupnames] }"""
host_groups = self._get_host_groups(hosts, self._groups.values())
return host_groups
def get_group_services(self):
"""return { groupname : [servicenames] }"""
group_services = {}
for group in self._groups.values():
group_services[group.name] = []
for child in group.children:
group_services[group.name].append(child.name)
return group_services
def _get_host_groups(self, hosts, groups):
host_groups = {}
for group in groups:
if group.children:
hosts_children = self._get_host_groups(hosts, group.children)
host_groups.update(hosts_children)
for host in hosts:
if host.name in group._hosts:
if host.name not in host_groups:
host_groups[host.name] = []
host_groups[host.name].append(group.name)
return host_groups
def get_group_hosts(self):
"""return { groupname : [hostnames] }"""
group_hosts = {}
for group in self._groups.values():
group_hosts[group.name] = []
for host in group.get_hosts():
group_hosts[group.name].append(host.name)
return group_hosts
def get_ansible_json(self):
"""generate json inventory for ansible

113
kollacli/group.py Normal file
View File

@ -0,0 +1,113 @@
# 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
import traceback
from kollacli.ansible.inventory import Inventory
from kollacli.exceptions import CommandError
from cliff.command import Command
from cliff.lister import Lister
class GroupAdd(Command):
"""Add group to open-stack-kolla"""
log = logging.getLogger(__name__)
def get_parser(self, prog_name):
parser = super(GroupAdd, self).get_parser(prog_name)
parser.add_argument('groupname', metavar='<groupname>',
help='group')
return parser
def take_action(self, parsed_args):
try:
groupname = parsed_args.groupname.strip()
inventory = Inventory.load()
inventory.add_group(groupname)
Inventory.save(inventory)
except CommandError as e:
raise e
except Exception as e:
raise Exception(traceback.format_exc())
class GroupRemove(Command):
"""Remove group from openstack-kolla"""
log = logging.getLogger(__name__)
def get_parser(self, prog_name):
parser = super(GroupRemove, self).get_parser(prog_name)
parser.add_argument('groupname', metavar='<groupname>',
help='group name')
return parser
def take_action(self, parsed_args):
try:
groupname = parsed_args.groupname.strip()
inventory = Inventory.load()
inventory.remove_group(groupname)
Inventory.save(inventory)
except CommandError as e:
raise e
except Exception as e:
raise Exception(traceback.format_exc())
class GroupListservices(Lister):
"""List all groups and their services"""
log = logging.getLogger(__name__)
def take_action(self, parsed_args):
try:
inventory = Inventory.load()
data = []
group_services = inventory.get_group_services()
if group_services:
for (groupname, servicenames) in group_services.items():
data.append((groupname, servicenames))
else:
data.append(('', ''))
return (('Group Name', 'Services'), sorted(data))
except CommandError as e:
raise e
except Exception as e:
raise Exception(traceback.format_exc())
class GroupListhosts(Lister):
"""List all groups and their hosts"""
log = logging.getLogger(__name__)
def take_action(self, parsed_args):
try:
inventory = Inventory.load()
data = []
group_hosts = inventory.get_group_hosts()
if group_hosts:
for (groupname, hostnames) in group_hosts.items():
data.append((groupname, hostnames))
else:
data.append(('', ''))
return (('Group Name', 'Hosts'), sorted(data))
except CommandError as e:
raise e
except Exception as e:
raise Exception(traceback.format_exc())

View File

@ -14,28 +14,21 @@
import argparse
import getpass
import logging
import traceback
from kollacli.ansible.inventory import Inventory
from kollacli import exceptions
from kollacli.i18n import _
from kollacli.objects.zones import Zones
from kollacli.exceptions import CommandError
from cliff.command import Command
from cliff.lister import Lister
def _host_not_found(log, hostname):
raise exceptions.CommandError(
raise CommandError(
'ERROR: Host (%s) not found. ' % hostname +
'Please add it with "host add"')
def _zone_not_found(log, zonename):
raise exceptions.CommandError(
'ERROR: Zone (%s) not found. ' % zonename +
'Please add it with "zone add"')
class HostAdd(Command):
"""Add host to open-stack-kolla"""
log = logging.getLogger(__name__)
@ -49,12 +42,17 @@ class HostAdd(Command):
return parser
def take_action(self, parsed_args):
hostname = parsed_args.hostname.strip()
groupname = parsed_args.groupname.strip()
try:
hostname = parsed_args.hostname.strip()
groupname = parsed_args.groupname.strip()
inventory = Inventory.load()
inventory.add_host(hostname, groupname)
Inventory.save(inventory)
inventory = Inventory.load()
inventory.add_host(hostname, groupname)
Inventory.save(inventory)
except CommandError as e:
raise e
except Exception as e:
raise Exception(traceback.format_exc())
class HostRemove(Command):
@ -74,13 +72,18 @@ class HostRemove(Command):
return parser
def take_action(self, parsed_args):
hostname = parsed_args.hostname.strip()
groupname = None
if parsed_args.groupname:
groupname = parsed_args.groupname.strip()
inventory = Inventory.load()
inventory.remove_host(hostname, groupname)
Inventory.save(inventory)
try:
hostname = parsed_args.hostname.strip()
groupname = None
if parsed_args.groupname:
groupname = parsed_args.groupname.strip()
inventory = Inventory.load()
inventory.remove_host(hostname, groupname)
Inventory.save(inventory)
except CommandError as e:
raise e
except Exception as e:
raise Exception(traceback.format_exc())
class HostList(Lister):
@ -89,90 +92,21 @@ class HostList(Lister):
log = logging.getLogger(__name__)
def take_action(self, parsed_args):
inventory = Inventory.load()
try:
inventory = Inventory.load()
hosts = inventory.get_hosts()
data = []
host_groups = inventory.get_host_groups(hosts)
if host_groups:
for (hostname, groupnames) in host_groups.items():
data.append((hostname, groupnames))
else:
data.append(('', ''))
return (('Host Name', 'Groups'), sorted(data))
class HostSetzone(Command):
"""Add a host to a zone"""
log = logging.getLogger(__name__)
def get_parser(self, prog_name):
parser = super(HostSetzone, self).get_parser(prog_name)
parser.add_argument('hostname', metavar='<hostname>', help='host name')
parser.add_argument('zone', metavar='[zone]', help='zone name')
return parser
def take_action(self, parsed_args):
hostname = parsed_args.hostname.strip()
zonename = parsed_args.zone.strip()
if zonename not in Zones().get_all():
_zone_not_found(self.log, zonename)
return False
hosts = Inventory()
host = hosts.get_host(hostname)
if not host:
_host_not_found(self.log, hostname)
return False
host.zone = zonename
hosts.save()
class HostClearzone(Command):
"""Clear the zone from a host"""
log = logging.getLogger(__name__)
def get_parser(self, prog_name):
parser = super(HostClearzone, self).get_parser(prog_name)
parser.add_argument('hostname', metavar='<hostname>', help='host name')
return parser
def take_action(self, parsed_args):
hostname = parsed_args.hostname.strip()
hosts = Inventory()
host = hosts.get_host(hostname)
if not host:
_host_not_found(self.log, hostname)
return False
host.zone = ''
hosts.save()
class HostAddservice(Command):
"""add service to a host"""
log = logging.getLogger(__name__)
def take_action(self, parsed_args):
self.log.info(_('host addservice'))
self.app.stdout.write(parsed_args)
class HostRemoveservice(Command):
"""Remove service from a host"""
log = logging.getLogger(__name__)
def take_action(self, parsed_args):
self.log.info(_('host removeservice'))
self.app.stdout.write(parsed_args)
data = []
host_groups = inventory.get_host_groups()
if host_groups:
for (hostname, groupnames) in host_groups.items():
data.append((hostname, groupnames))
else:
data.append(('', ''))
return (('Host Name', 'Groups'), sorted(data))
except CommandError as e:
raise e
except Exception as e:
raise Exception(traceback.format_exc())
class HostCheck(Command):
@ -186,15 +120,20 @@ class HostCheck(Command):
return parser
def take_action(self, parsed_args):
hostname = parsed_args.hostname.strip()
try:
hostname = parsed_args.hostname.strip()
inventory = Inventory.load()
host = inventory.get_host(hostname)
if not host:
_host_not_found(self.log, hostname)
return False
inventory = Inventory.load()
host = inventory.get_host(hostname)
if not host:
_host_not_found(self.log, hostname)
return False
host.check()
host.check()
except CommandError as e:
raise e
except Exception as e:
raise Exception(traceback.format_exc())
class HostInstall(Command):
@ -209,19 +148,24 @@ class HostInstall(Command):
return parser
def take_action(self, parsed_args):
hostname = parsed_args.hostname.strip()
inventory = Inventory.load()
host = inventory.get_host(hostname)
if not host:
_host_not_found(self.log, hostname)
return False
try:
hostname = parsed_args.hostname.strip()
inventory = Inventory.load()
host = inventory.get_host(hostname)
if not host:
_host_not_found(self.log, hostname)
return False
if parsed_args.insecure:
password = parsed_args.insecure.strip()
else:
password = getpass.getpass('Root password for %s: ' % hostname)
if parsed_args.insecure:
password = parsed_args.insecure.strip()
else:
password = getpass.getpass('Root password for %s: ' % hostname)
host.install(password)
host.install(password)
except CommandError as e:
raise e
except Exception as e:
raise Exception(traceback.format_exc())
class HostUninstall(Command):
@ -236,15 +180,20 @@ class HostUninstall(Command):
return parser
def take_action(self, parsed_args):
hostname = parsed_args.hostname.strip()
inventory = Inventory.load()
host = inventory.get_host(hostname)
if not host:
_host_not_found(self.log, hostname)
return False
try:
hostname = parsed_args.hostname.strip()
inventory = Inventory.load()
host = inventory.get_host(hostname)
if not host:
_host_not_found(self.log, hostname)
return False
if parsed_args.insecure:
password = parsed_args.insecure.strip()
else:
password = getpass.getpass('Root password for %s: ' % hostname)
host.uninstall(password)
if parsed_args.insecure:
password = parsed_args.insecure.strip()
else:
password = getpass.getpass('Root password for %s: ' % hostname)
host.uninstall(password)
except CommandError as e:
raise e
except Exception as e:
raise Exception(traceback.format_exc())

View File

@ -31,11 +31,13 @@ console_scripts =
kollacli = kollacli.shell:main
kolla.cli =
group_add = kollacli.group:GroupAdd
group_remove = kollacli.group:GroupRemove
group_listservices = kollacli.group:GroupListservices
group_listhosts = kollacli.group:GroupListhosts
host_add = kollacli.host:HostAdd
host_remove = kollacli.host:HostRemove
host_list = kollacli.host:HostList
host_setzone = kollacli.host:HostSetzone
host_clearzone = kollacli.host:HostClearzone
host_addservice = kollacli.host:HostAddservice
host_removeservice = kollacli.host:HostRemoveservice
host_check = kollacli.host:HostCheck

View File

@ -66,33 +66,6 @@ class TestFunctional(KollaCliTest):
msg = self.run_client_cmd('host list -f json')
self._check_cli_output(hosts, msg)
# def test_host_setzone(self):
# hosts = self.TestHosts()
# hostname = 'host_test1'
# 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)
#
# 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):
test_hosts = TestHosts()
test_hosts.load()