diff --git a/kolla_kubernetes/cli/__init__.py b/kolla_kubernetes/cli/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/kolla_kubernetes/cli/service.py b/kolla_kubernetes/cli/service.py new file mode 100644 index 000000000..369e6d159 --- /dev/null +++ b/kolla_kubernetes/cli/service.py @@ -0,0 +1,46 @@ +# 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 cliff import command +from oslo_config import cfg +from oslo_log import log + + +from kolla_kubernetes import service + +CONF = cfg.CONF +LOG = log.getLogger(__name__) + + +class Run(command.Command): + """Run a service.""" + + def get_parser(self, prog_name): + parser = super(Run, self).get_parser(prog_name) + parser.add_argument('service') + return parser + + def take_action(self, parsed_args): + service.run_service(parsed_args.service, + CONF.service_dir) + + +class Kill(command.Command): + """Kill a service.""" + + def get_parser(self, prog_name): + parser = super(Kill, self).get_parser(prog_name) + parser.add_argument('service') + return parser + + def take_action(self, parsed_args): + service.kill_service(parsed_args.service) diff --git a/kolla_kubernetes/cmd/__init__.py b/kolla_kubernetes/cmd/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/kolla_kubernetes/cmd/shell.py b/kolla_kubernetes/cmd/shell.py new file mode 100644 index 000000000..afeb5563f --- /dev/null +++ b/kolla_kubernetes/cmd/shell.py @@ -0,0 +1,157 @@ +# 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 os.path +import shlex +import sys + +from cliff import app +from cliff import commandmanager +from cliff import interactive +from oslo_config import cfg +from oslo_log import log + +from kolla_kubernetes.common import file_utils +from kolla_kubernetes.common import utils + +PROJECT = 'kolla_kubernetes' +VERSION = '1.0' + +CONF = cfg.CONF + +log.register_options(CONF) +log.set_defaults( + default_log_levels='requests.packages.urllib3.connectionpool=WARNING') + +cli_opts = [ + cfg.StrOpt('service-dir', + default=utils.env( + 'KM_SERVICE_DIR', default=os.path.join( + file_utils.find_base_dir(), 'services')), + help='Directory with services, (Env: KM_SERVICE_DIR)'), +] +CONF.register_cli_opts(cli_opts) + + +class KollaKubernetesInteractiveApp(interactive.InteractiveApp): + def do_run(self, arg): + self.default(arg) + + def do_help(self, arg): + line_parts = shlex.split(arg) + try: + self.command_manager.find_command(line_parts) + return self.default(self.parsed('help ' + arg)) + except ValueError: + # There is a builtin cmd2 command + pass + return interactive.InteractiveApp.do_help(self, arg) + + +class KollaKubernetesShell(app.App): + def __init__(self): + super(KollaKubernetesShell, self).__init__( + description='Kolla-kubernetes command-line interface', + version=VERSION, + command_manager=commandmanager.CommandManager('kolla_kubernetes.cli'), + deferred_help=True, + interactive_app_factory=KollaKubernetesInteractiveApp + ) + + def configure_logging(self): + return + + def initialize_app(self, argv): + self.options.service_dir = CONF.service_dir + + def print_help(self): + outputs = [] + max_len = 0 + self.stdout.write('\nCommands :\n') + + for name, ep in sorted(self.command_manager): + factory = ep.load() + cmd = factory(self, None) + one_liner = cmd.get_description().split('\n')[0] + outputs.append((name, one_liner)) + max_len = max(len(name), max_len) + + for name, one_liner in outputs: + self.stdout.write(' %s %s\n' % (name.ljust(max_len), one_liner)) + + +def _separate_args(argv): + conf_opts = _config_opts_map() + config_args = [] + command_args = argv[:] + while command_args: + nargs = conf_opts.get(command_args[0]) + if nargs: + config_args.extend(command_args[:nargs]) + command_args = command_args[nargs:] + else: + break + return config_args, command_args + + +def _config_opts_map(): + opts = {'--help': 1, '-h': 1, '--config-dir': 2, '--config-file': 2, + '--version': 1} + for opt in CONF._all_cli_opts(): + if opt[1]: + arg = '%s-%s' % (opt[1].name, opt[0].name) + else: + arg = opt[0].name + + if isinstance(opt[0], cfg.BoolOpt): + nargs = 1 + opts['--no%s' % arg] = 1 + else: + nargs = 2 + opts['--%s' % arg] = nargs + + if opt[0].short: + opts['-%s' % opt[0].short] = nargs + + for dep_opt in opt[0].deprecated_opts: + if getattr(dep_opt, 'group'): + opts['--%s-%s' % (dep_opt.group, dep_opt.name)] = nargs + else: + opts['--%s' % dep_opt.name] = nargs + + return opts + + +def main(argv=sys.argv[1:]): + config_args, command_args = _separate_args(argv) + + need_help = (['help'] == command_args or '-h' in config_args or + '--help' in config_args) + if need_help: + CONF([], project=PROJECT, version=VERSION) + CONF.print_help() + return KollaKubernetesShell().print_help() + + CONF(config_args, project=PROJECT, version=VERSION) + log.setup(CONF, PROJECT, VERSION) + + if '-d' in config_args or '--debug' in config_args: + command_args.insert(0, '--debug') + CONF.log_opt_values( + log.getLogger(PROJECT), log.INFO) + + return KollaKubernetesShell().run(command_args) + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/kolla_kubernetes/common/__init__.py b/kolla_kubernetes/common/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/kolla_kubernetes/common/file_utils.py b/kolla_kubernetes/common/file_utils.py new file mode 100644 index 000000000..0271be69b --- /dev/null +++ b/kolla_kubernetes/common/file_utils.py @@ -0,0 +1,108 @@ +# 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 errno +import logging +import os +import platform +import sys + +from oslo_utils import importutils + + +LOG = logging.getLogger(__name__) + + +class KollaException(Exception): + pass + + +class KollaDirNotFoundException(KollaException): + pass + + +class KollaNotFoundException(KollaException): + def __init__(self, message, entity='file'): + super(KollaNotFoundException, self).__init__( + 'The %s "%s" was not found' % (entity, message)) + + +def find_os_type(): + return platform.linux_distribution()[0] + + +def mkdir_p(path): + try: + os.makedirs(path) + except OSError as exc: # Python >2.5 + if exc.errno == errno.EEXIST and os.path.isdir(path): + pass + else: + raise + + +def get_src_dir(): + kolla_kubernetes = importutils.import_module('kolla_kubernetes') + mod_path = os.path.abspath(kolla_kubernetes.__file__) + # remove the file and module to get to the base. + return os.path.dirname(os.path.dirname(mod_path)) + + +def find_base_dir(): + script_path = os.path.dirname(os.path.realpath(sys.argv[0])) + base_script_path = os.path.basename(script_path) + if base_script_path == 'kolla-kubernetes': + return script_path + if base_script_path == 'kolla_kubernetes': + return os.path.join(script_path, '..') + if base_script_path == 'cmd': + return os.path.join(script_path, '..', '..') + if base_script_path == 'subunit': + return get_src_dir() + if base_script_path == 'bin': + if find_os_type() in ['Ubuntu', 'debian']: + base_dir = '/usr/local/share/kolla-kubernetes' + else: + base_dir = '/usr/share/kolla-kubernetes' + + if os.path.exists(base_dir): + return base_dir + else: + return get_src_dir() + raise KollaDirNotFoundException( + 'I do not know where your Kolla directory is' + ) + + +def find_config_file(filename): + filepath = os.path.join('/etc/kolla-kubernetes', filename) + if os.access(filepath, os.R_OK): + config_file = filepath + else: + config_file = os.path.join(find_base_dir(), + 'etc', filename) + return config_file + + +POSSIBLE_PATHS = set([ + '/usr/share/kolla-kubernetes', + get_src_dir(), + find_base_dir() +]) + + +def find_file(filename): + for path in POSSIBLE_PATHS: + file_path = os.path.join(path, filename) + if os.path.exists(file_path): + return file_path + raise KollaNotFoundException(filename, entity='file') diff --git a/kolla_kubernetes/common/utils.py b/kolla_kubernetes/common/utils.py new file mode 100644 index 000000000..69f808e2c --- /dev/null +++ b/kolla_kubernetes/common/utils.py @@ -0,0 +1,46 @@ +# 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 collections +import os +from six.moves.urllib import parse + + +def env(*args, **kwargs): + for arg in args: + value = os.environ.get(arg) + if value: + return value + return kwargs.get('default', '') + + +def dict_update(d, u): + """Recursively update 'd' with 'u' and return the result.""" + + if not isinstance(u, collections.Mapping): + return u + + for k, v in u.items(): + if isinstance(v, collections.Mapping): + d[k] = dict_update(d.get(k, {}), v) + else: + d[k] = u[k] + return d + + +def get_query_string(search_opts): + if search_opts: + qparams = sorted(search_opts.items(), key=lambda x: x[0]) + query_string = "?%s" % parse.urlencode(qparams, doseq=True) + else: + query_string = "" + return query_string diff --git a/kolla_kubernetes/service.py b/kolla_kubernetes/service.py new file mode 100644 index 000000000..7fc10d4f5 --- /dev/null +++ b/kolla_kubernetes/service.py @@ -0,0 +1,51 @@ +# 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. + +def run_service(service_name, service_dir, variables=None): + # generate zk variables + if service_name == 'nova-compute': + service_list = ['nova-compute', 'nova-libvirt', 'openvswitch-vswitchd', + 'neutron-openvswitch-agent', 'openvswitch-db'] + elif service_name == 'network-node': + service_list = ['neutron-openvswitch-agent', 'neutron-dhcp-agent', + 'neutron-metadata-agent', 'openvswitch-vswitchd', + 'openvswitch-db neutron-l3-agent'] + #TODO: load this service _list from config + elif service_name == 'all': + service_list = ['keystone-init', 'keystone-api', 'keystone-db-sync', + 'glance-init', 'mariadb', 'rabbitmq', 'glance-registry', + 'glance-api', 'nova-init', 'nova-api', 'nova-scheduler', + 'nova-conductor', 'nova-consoleauth', 'neutron-init', + 'neutron-server', 'horizon', 'nova-compute', + 'nova-libvirt', 'openvswitch-vswitchd', + 'neutron-openvswitch-agent', 'openvswitch-db', + 'neutron-dhcp-agent', 'neutron-metadata-agent', + 'openvswitch-db neutron-l3-agent'] + elif service_name == 'zookeeper': + service_list = [] + else: + service_list = [service_name] + # for service in service_list: + # _build_runner(service, service_dir, variables=variables) + # _deploy_instance(service_name) + + +def kill_service(service_name): + # if service_name == "all": + # with zk_utils.connection() as zk: + # status_node = os.path.join('kolla', CONF.kolla.deployment_id, + # 'status') + # zk.delete(status_node, recursive=True) + # _delete_instance(service_name) + pass + + diff --git a/setup.cfg b/setup.cfg index 4d74ff6c9..64c5a4c12 100644 --- a/setup.cfg +++ b/setup.cfg @@ -21,7 +21,17 @@ classifier = [files] packages = - kolla-kubernetes + kolla_kubernetes +data_files = + share/kolla-kubernetes/services = services/* + +[entry_points] +console_scripts = + kolla-kubernetes = kolla_kubernetes.cmd.shell:main + +kolla_kubernetes.cli = + run = kolla_kubernetes.cli.service:Run + kill = kolla_kubernetes.cli.service:Kill [build_sphinx] source-dir = doc/source