# Copyright 2019 Nokia # 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 print_function import sys import inspect import socket import pprint import prettytable from cmframework.apis import cmmanage from cmframework.apis import cmerror class VerboseLogger(object): def __call__(self, msg): print(msg) class CMCLIHandler(object): def __init__(self): self.api = None self.verbose_logger = VerboseLogger() def _init_api(self, ip, port, client_lib, verbose): logger = None if verbose: logger = self.verbose_logger try: serverip = socket.gethostbyname(ip) except Exception: # pylint: disable=broad-except # use localhost in-case we cannot resolve the provided hostname serverip = '127.0.0.1' self.api = cmmanage.CMManage(serverip, port, client_lib, logger) def set_handler(self, subparser): subparser.set_defaults(handler=self) # pylint: disable=no-self-use, unused-argument def init_subparser(self, subparsers): raise cmerror.CMError('Not implemented') # pylint: disable=no-self-use, unused-argument def __call__(self, args): raise cmerror.CMError('Not implemented') class CMCLIGetPropertyHandler(CMCLIHandler): def init_subparser(self, subparsers): subparser = subparsers.add_parser('get-property', help='Get a property value') subparser.add_argument('--property', required=True, dest='name', metavar='NAME', action='store') subparser.add_argument('--snapshot', required=False, dest='snapshot', metavar='SNAPSHOT-NAME', action='store') self.set_handler(subparser) def __call__(self, args): self._init_api(args.ip, args.port, args.client_lib, args.verbose) name = args.name snapshot = args.snapshot value = self.api.get_property(name, snapshot) print(value) class CMCLIGetPropertiesHandler(CMCLIHandler): def init_subparser(self, subparsers): subparser = subparsers.add_parser('get-properties', help='Get the properties matching a filter') subparser.add_argument('--matching-filter', required=True, dest='matching_filter', metavar='MATCHING-FILTER', action='store') subparser.add_argument('--snapshot', required=False, dest='snapshot', metavar='SNAPSHOT-NAME', action='store') self.set_handler(subparser) def __call__(self, args): self._init_api(args.ip, args.port, args.client_lib, args.verbose) matching_filter = args.matching_filter snapshot = args.snapshot props = self.api.get_properties(matching_filter, snapshot) for name, value in props.iteritems(): print('%s=%s' % (name, value)) class CMCLISetPropertyHandler(CMCLIHandler): def init_subparser(self, subparsers): subparser = subparsers.add_parser('set-property', help='Set a property') subparser.add_argument('--property', required=True, dest='prop', metavar='NAME VALUE', action='store', nargs=2) self.set_handler(subparser) def __call__(self, args): self._init_api(args.ip, args.port, args.client_lib, args.verbose) prop = args.prop change_uuid = self.api.set_property(prop[0], prop[1]) print("change-uuid:%s" % change_uuid) class CMCLISetPropertiesHandler(CMCLIHandler): def init_subparser(self, subparsers): subparser = subparsers.add_parser('set-properties', help='Set a group of properties') subparser.add_argument('--property', required=True, dest='props', metavar='NAME VALUE', action='append', nargs=2) self.set_handler(subparser) def __call__(self, args): self._init_api(args.ip, args.port, args.client_lib, args.verbose) props = args.props dic = {} for prop in props: name = prop[0] value = prop[1] dic[name] = value change_uuid = self.api.set_properties(dic) print("change-uuid:%s" % change_uuid) class CMCLIDeletePropertyHandler(CMCLIHandler): def init_subparser(self, subparsers): subparser = subparsers.add_parser('delete-property', help='Delete a property') subparser.add_argument('--property', required=True, dest='name', metavar='NAME', action='store') self.set_handler(subparser) def __call__(self, args): self._init_api(args.ip, args.port, args.client_lib, args.verbose) name = args.name change_uuid = self.api.delete_property(name) print("change-uuid:%s" % change_uuid) class CMCLIDeletePropertiesWithFilterHandler(CMCLIHandler): def init_subparser(self, subparsers): subparser = subparsers.add_parser('delete-properties-with-filter', help='Delete properties matching a filter') subparser.add_argument('--matching-filter', required=True, dest='matching_filter', metavar='MATCHING-FILTER', action='store') self.set_handler(subparser) def __call__(self, args): self._init_api(args.ip, args.port, args.client_lib, args.verbose) matching_filter = args.matching_filter change_uuid = self.api.delete_properties(matching_filter) print("change-uuid:%s" % change_uuid) class CMCLIDeletePropertiesHandler(CMCLIHandler): def init_subparser(self, subparsers): subparser = subparsers.add_parser('delete-properties', help='Delete a group of properties') subparser.add_argument('--property', required=True, dest='props', metavar='PROPERY-NAME', action='append') self.set_handler(subparser) def __call__(self, args): self._init_api(args.ip, args.port, args.client_lib, args.verbose) props = args.props change_uuid = self.api.delete_properties(props) print("change-uuid:%s" % change_uuid) class CMCLICreateSnapshotHandler(CMCLIHandler): def init_subparser(self, subparsers): subparser = subparsers.add_parser('create-snapshot', help='Take a snapshot of the configuration data') subparser.add_argument('--name', required=True, dest='snapshot_full_name', metavar='SNAPSHOT-FULL-NAME', action='store') self.set_handler(subparser) def __call__(self, args): self._init_api(args.ip, args.port, args.client_lib, args.verbose) snapshot = args.snapshot_full_name self.api.create_snapshot(snapshot) class CMCLIRestoreSnapshotHandler(CMCLIHandler): def init_subparser(self, subparsers): subparser = subparsers.add_parser('restore-snapshot', help='Restore a configuration snapshot') subparser.add_argument('--name', required=True, dest='snapshot_full_name', metavar='SNAPSHOT-FULL-NAME', action='store') self.set_handler(subparser) def __call__(self, args): self._init_api(args.ip, args.port, args.client_lib, args.verbose) snapshot = args.snapshot_full_name self.api.restore_snapshot(snapshot) class CMCLIDeleteSnapshotHandler(CMCLIHandler): def init_subparser(self, subparsers): subparser = subparsers.add_parser('delete-snapshot', help='Delete a configuration snapshot') subparser.add_argument('--name', required=True, dest='snapshot_full_name', metavar='SNAPSHOT-FULL-NAME', action='store') self.set_handler(subparser) def __call__(self, args): self._init_api(args.ip, args.port, args.client_lib, args.verbose) snapshot = args.snapshot_full_name self.api.delete_snapshot(snapshot) class CMCLIListSnapshotHandler(CMCLIHandler): def init_subparser(self, subparsers): subparser = subparsers.add_parser('list-snapshots', help='List all configuration snapshots') self.set_handler(subparser) def __call__(self, args): self._init_api(args.ip, args.port, args.client_lib, args.verbose) snapshots = self.api.list_snapshots() sorted_snapshots = sorted(snapshots, key=lambda k: k['creation_date']) t = prettytable.PrettyTable(['Name', 'Date', 'Release', 'Build']) t.set_style(prettytable.PLAIN_COLUMNS) t.align = 'l' for snapshot in sorted_snapshots: t.add_row([snapshot['name'], snapshot['creation_date'], snapshot['release'], snapshot['build']]) print(t) class CMCLIActivateHandler(CMCLIHandler): def init_subparser(self, subparsers): subparser = subparsers.add_parser( 'activate', help='Activate the configuration in all or specified node') subparser.add_argument('--node-name', required=False, dest='node_name', metavar='NODE-NAME', action='store') self.set_handler(subparser) def __call__(self, args): self._init_api(args.ip, args.port, args.client_lib, args.verbose) node_name = args.node_name self.api.activate(node_name) class CMCLIRebootHandler(CMCLIHandler): def init_subparser(self, subparsers): subparser = subparsers.add_parser('reboot-request', help=('Request reboot of a specified node ' 'during activation')) subparser.add_argument('--node-name', required=True, dest='node_name', metavar='NODE-NAME', action='store') self.set_handler(subparser) def __call__(self, args): self._init_api(args.ip, args.port, args.client_lib, args.verbose) node_name = args.node_name self.api.reboot_node(node_name) class CMCLIBootstrapHandler(CMCLIHandler): def init_subparser(self, subparsers): subparser = subparsers.add_parser('bootstrap', help='Bootsrap the backend with the user config data') subparser.add_argument('--config', required=True, dest='config', metavar='INITIAL-USER-CONFIG', action='store') subparser.add_argument('--plugin_path', required=True, dest='plugin_path', metavar='BOOTSTRAP-PLUGIN-PATH', action='store') self.set_handler(subparser) def __call__(self, args): self._init_api(args.ip, args.port, args.client_lib, args.verbose) from cmframework.utils.cmuserconfig import UserConfig uc = UserConfig(args.config, args.plugin_path) flat_config = uc.get_flat_config() self.api.set_properties(flat_config) class CMCLIAnsibleInventoryHandler(CMCLIHandler): def init_subparser(self, subparsers): subparser = subparsers.add_parser('ansible-inventory', help='Prints the ansible inventory json to output') subparser.add_argument('--plugin_path', required=False, default='/opt/cmframework/inventoryhandlers', dest='plugin_path', metavar='INVENTORY-HANDLERS-PLUGIN-PATH', action='store') self.set_handler(subparser) def __call__(self, args): self._init_api(args.ip, args.port, args.client_lib, args.verbose) from cmframework.utils.cmansibleinventory import AnsibleInventory import json properties = self.api.get_properties('.*') inventory = AnsibleInventory(properties, args.plugin_path) inv = inventory.generate_inventory() print (json.dumps(inv, indent=4, sort_keys=True)) class CMAnsiblePlaybookHandler(CMCLIHandler): def init_subparser(self, subparsers): subparser = subparsers.add_parser('ansible-playbooks-generate', help=('Generate the ansible playbooks for the ' 'bootstrapping, provisioning, ' 'postconfig and finalizing phases')) subparser.add_argument('--bootstrapping-playbooks-path', required=False, default='/etc/lcm/playbooks/installation/bootstrapping', dest='bootstrapping_path', metavar='BOOTSTRAPPING-PLAYBOOKS-PATH', action='store') subparser.add_argument('--provisioning-playbooks-path', required=False, default='/etc/lcm/playbooks/installation/provisioning', dest='provisioning_path', metavar='PROVISIONING-PLAYBOOKS-PATH', action='store') subparser.add_argument('--postconfig-playbooks-path', required=False, default='/etc/lcm/playbooks/installation/postconfig', dest='postconfig_path', metavar='POSTCONFIG-PLAYBOOKS-PATH', action='store') subparser.add_argument('--finalize-playbooks-path', required=False, default='/etc/lcm/playbooks/installation/finalize', dest='finalize_path', metavar='FINALIZE-PLAYBOOKS-PATH', action='store') subparser.add_argument('--destination-path', required=False, default='/opt/openstack-ansible/playbooks/', dest='destination_path', metavar='DESTINATION-PATH', action='store') self.set_handler(subparser) def __call__(self, args): from cmframework.utils.cmansibleplaybooks import AnsiblePlaybooks playbooks = AnsiblePlaybooks(args.destination_path, args.bootstrapping_path, args.provisioning_path, args.postconfig_path, args.finalize_path) playbooks.generate_playbooks() class CMCLIDisableAutomaticActivationHandler(CMCLIHandler): def init_subparser(self, subparsers): subparser = subparsers.add_parser('disable-automatic-activation', help='Disable automatic activation') self.set_handler(subparser) def __call__(self, args): self._init_api(args.ip, args.port, args.client_lib, args.verbose) self.api.disable_automatic_activation() class CMCLIEnableAutomaticActivationHandler(CMCLIHandler): def init_subparser(self, subparsers): subparser = subparsers.add_parser('enable-automatic-activation', help='Enable automatic activation') self.set_handler(subparser) def __call__(self, args): self._init_api(args.ip, args.port, args.client_lib, args.verbose) self.api.enable_automatic_activation() class CMCLIGetChangesStatesHandler(CMCLIHandler): def init_subparser(self, subparsers): subparser = subparsers.add_parser('get-changes-states', help='Get the configuration changes states') subparser.add_argument('--uuid', required=False, dest='change_uuid', metavar='CHANGE_UUID', action='store') self.set_handler(subparser) def __call__(self, args): self._init_api(args.ip, args.port, args.client_lib, args.verbose) change_uuid = None if args.change_uuid: change_uuid = args.change_uuid result = self.api.get_changes_states(change_uuid) pp = pprint.PrettyPrinter(indent=4) pp.pprint(result) def get_handlers_list(): handlers = [] for name, obj in inspect.getmembers(sys.modules[__name__]): if inspect.isclass(obj): if name != 'CMCLIHandler': if issubclass(obj, CMCLIHandler): handlers.append(obj()) return handlers def main(): handlers = get_handlers_list() for handler in handlers: print('handler is ', handler) if __name__ == '__main__': main()