/
opt
/
cloudlinux
/
venv
/
lib
/
python3.11
/
site-packages
/
clselector
/
Upload Filee
HOME
# -*- coding: utf-8 -*- # Command line arguments parser for cloudlinux-selector utility # cloudlinux-license Utility to check/set Cloudlinux license # # Copyright © Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2019 All Rights Reserved # # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENSE.TXT from __future__ import absolute_import from __future__ import print_function from __future__ import division import json import os from docopt import docopt from docopt import DocoptExit from schema import Schema, And, Use, Or, SchemaError from .selectorlib import CloudlinuxSelectorLib NODEJS = 'nodejs' PYTHON = 'python' RUBY = 'ruby' PHP = 'php' def _ensure_command_allowed(interpreter, args, as_from_root, selector_status): """ Do some additional checks to restrict commands not available for current user or interpreter or whatever and do this only after args parsing """ if not as_from_root and any([ args["install-version"], args["uninstall-version"], args["enable-version"], args["disable-version"], ]): raise SchemaError( None, 'This command should be run from administrator only') if interpreter != NODEJS and any([ args["change-version-multiple"], ]): raise SchemaError(None, 'This command is supported only for NodeJS') if interpreter != PYTHON and any([ args["import-applications"], args["migrate"], args["uninstall-modules"], ]): raise SchemaError(None, 'This command is supported only for Python') if interpreter not in (NODEJS, PYTHON) and any([ args["enable-version"], args["disable-version"], args["create"], args["read-config"], args["save-config"], args["install-version"], args["uninstall-version"], args["start"], args["restart"], args["stop"], args["destroy"], args["install-modules"], args["run-script"], ]): raise SchemaError(None, 'This command is supported only for NodeJS and Python') if interpreter != PHP and (args["make-defaults-config"] or args['setup']): raise SchemaError(None, 'This command is supported only for %s' % PHP) if not as_from_root and any([ args['make-defaults-config'], args['setup'], args['--selector-status'], args['--default-version'], args['--supported-versions'] ]): raise SchemaError(None, 'Specified option(s) only for root') if interpreter != PYTHON and any([ args["--entry-point"] ]): raise SchemaError(None, 'This options(s) only for Python') if interpreter in (NODEJS, PYTHON) and not args['get'] and not selector_status and not _run_from_admin(): raise SchemaError(None, 'Selector is disabled') def _run_from_admin(): """ Check who is owner of the parent process. if owner is root - return True if parent process can't be found - return True :return: """ try: return os.stat(os.path.join('/proc/', str(os.getppid()))).st_uid == 0 except OSError: return True def parse_cloudlinux_selector_opts(argv, _is_json_need=False, as_from_root=True): """ Parse arguments for cloudlinux-selector command :param argv: sys.argv :param _is_json_need: sys.argv contains --json key :param as_from_root: True if we assume that root has called this util :return cortege: (error_flag, s_message) """ # program name prog_name = "cloudlinux-selector" docstring = """Utility to get/set Cloudlinux selector options Usage: {0} [get] [--json] [--interpreter <str>] [(--get-supported-versions | --get-default-version | --get-selector-status)] [(--user <str> | --domain <str>)] {0} get [--json] [--interpreter <str>] [--get-current-version] [--user <str>] {0} set [--json] [--interpreter <str>] (--selector-status <enabled,disabled> | --default-version <str> | --supported-versions <str> | --current-version <str>) [--user <str>] {0} set [--json] [--interpreter <str>] --version <str> (--extensions <str> | --options <str>) [--user <str>] {0} set [--json] [--interpreter <str>] [(--user <str> | --domain <str>)] --app-root <str> [--app-mode <str>] [--new-app-root <str>] [--new-domain <str>] [--new-app-uri <str>] [--new-version <str>] [--startup-file <str>] [--env-vars <str>] [--skip-web-check] [--entry-point <str>] [--config-files <str>] [--passenger-log-file <str>] {0} create [--json] [--interpreter <str>] [(--user <str> | --domain <str>)] --app-root <str> --app-uri <str> [--version <str>] [--app-mode <str>] [--startup-file <str>] [--entry-point <str>] [--env-vars <str>] [--passenger-log-file <str>] {0} set [--json] [--interpreter <str>] --reset-extensions --version <str> [--user <str>] {0} (enable-version | disable-version) [--json] [--interpreter <str>] --version <str> {0} install-modules [--json] [--interpreter <str>] [(--user <str> | --domain <str>)] --app-root <str> [(--requirements-file <str> | --modules <str>)] [--skip-web-check] {0} uninstall-modules [--json] [--interpreter <str>] [(--user <str> | --domain <str>)] --app-root <str> --modules <str> {0} install-version [--json] [--interpreter <str>] --version <str> {0} uninstall-version [--json] [--interpreter <str>] --version <str> {0} read-config [--json] [--interpreter <str>] [(--user <str> | --domain <str>)] --app-root <str> --config-file <str> {0} save-config [--json] [--interpreter <str>] [(--user <str> | --domain <str>)] --app-root <str> --config-file <str> --content <str> {0} (start | restart | stop | destroy) [--json] [--interpreter <str>] [(--user <str> | --domain <str>)] --app-root <str> {0} run-script [--json] [--interpreter <str>] [(--user <str> | --domain <str>)] --app-root <str> --script-name <str> {0} run-script [--json] [--interpreter <str>] [(--user <str> | --domain <str>)] --app-root <str> --script-name <str> -- <script_args>... {0} change-version-multiple --json --interpreter <str> --from-version <str> --new-version <str> {0} make-defaults-config [--json] [--interpreter <str>] {0} import-applications [--json] --interpreter <str> {0} migrate [--json] --interpreter <str> --user <str> --app-root <str> {0} setup [--json] --interpreter <str> {0} (-h | --help) Options: --json Return data in JSON format. --interpreter <str> One of php/nodejs/python, default is php --get-supported-versions Return info about supported versions --get-current-version Return current version of interpretator for user --get-default-version Return info about default version only --get-selector-status Return info about selector status --reset-extensions Replace user extensions with version default extensions --supported-versions <str> Set supported versions of interpreter --default-version <str> Set default version of interpreter --current-version <str> Set alternative as user default --selector-status <enabled|disabled> Set selector status enabled or disabled --version <str> Version of interpreter --extensions <str> JSON dict with extensions and their status --options <str> JSON dict with options and their values --user <str> Username to operate on --app-root <str> Root of an application to be created --domain <str> Domain to work in --app-uri <str> URI path to get the application being created --config-file <str> path to config file to be read or saved --config-files <str> names of config files (such as requirements.txt or etc) (only for python interpreter) --content <str> Base64-encoded config file contents to be saved --app-mode <str> Application mode --startup-file <str> Startup application file --env-vars <str> Environment variable as json string --new-app-root <str> Set new application directory --new-app-uri <str> Set new application uri --new-domain <str> Set new domain for application --new-version <str> Set new nodejs version for application --from-version <str> Old NodeJS version for group change version operations --script-name <str> Command for an npm script to be run --skip-web-check Skip check web application after change it's properties --entry-point <str> Use the specified entrypoint for application (only for python interpeter) --requirements-file <str> Use the specified file for install required modules --modules <str> Install comma-separated list of modules --passenger-log-file <str> Set passenger log full filename -h, --help Show this help message and exit """.format(prog_name) try: args = docopt(docstring, argv) except DocoptExit: s_error_string = 'ERROR: Invalid parameter passed' if not _is_json_need: s_error_string += "\n\n" + docstring return False, s_error_string interpreter = args.get('--interpreter') def _convert_version(x): """For the NodeJS, ignore all the version parts except the major one""" parts = x.split('.') if interpreter == NODEJS: return str(int(parts[0])) if interpreter == PYTHON: ver = x if len(parts) == 3: ver = x.rsplit('.', 1)[0] return ver return float(x) # keep old behavior for PHP _version_validator = Or(None, And(str, lambda x: x == "native"), And(str, Use(_convert_version)), error="Version must be Interpreter version number or native") def _json_string_to_dict(s_json): j_dict = json.loads(s_json) # json.loads in some cases returns a string instead dictionary. # So try to get keys to ensure that j_dict really dictionary list(j_dict.keys()) return j_dict s_json_error = '%s option should contain a valid JSON' s = Schema({ "get": bool, "set": bool, "import-applications": bool, "migrate": bool, "create": bool, "read-config": bool, "enable-version": bool, "disable-version": bool, "save-config": bool, "install-modules": bool, "uninstall-modules": bool, "start": bool, "restart": bool, "stop": bool, "destroy": bool, "install-version": bool, "uninstall-version": bool, "run-script": bool, "change-version-multiple": bool, "make-defaults-config": bool, "setup": bool, "<script_args>": Or(None, list), "--": bool, "--json": bool, "--help": bool, "--interpreter": Or(None, PHP, PYTHON, RUBY, NODEJS), "--get-supported-versions": bool, "--get-current-version": bool, "--get-default-version": bool, "--get-selector-status": bool, "--reset-extensions": bool, "--supported-versions": Or(None, And(str, Use(_json_string_to_dict)), error=s_json_error % "--supported-versions"), "--default-version": _version_validator, "--current-version": _version_validator, "--selector-status": Or(None, And(str, lambda x: x in ["enabled", "disabled"]), error="Selector status must be enabled or disabled"), "--version": _version_validator, "--extensions": Or(None, And(str, Use(_json_string_to_dict)), error=s_json_error % "--extensions"), "--options": Or(None, And(str, Use(_json_string_to_dict)), error=s_json_error % "--options"), "--user": Or(None, str), "--app-root": Or(None, str), "--domain": Or(None, str), "--app-uri": Or(None, str), "--config-file": Or(None, str), "--content": Or(None, str), "--app-mode": Or(None, str), "--startup-file": Or(None, And(str, lambda x: x != "package.json"), error='Cannot set "package.json" as startup file'), "--env-vars": Or(None, str), "--config-files": Or(None, str), "--new-app-root": Or(None, str), "--new-app-uri": Or(None, str), "--new-domain": Or(None, str), "--new-version": Or(None, str), "--from-version": Or(None, str), "--script-name": Or(None, str), "--entry-point": Or(None, str), "--requirements-file": Or(None, str), "--modules": Or(None, And(str, lambda x: bool(x)), error="modules should be a comma-separated list of packages"), "--skip-web-check": bool, "--passenger-log-file": Or(None, str) }) def _check_users_part_cli(_args): """ Check args for existing of mandatory arguments :param _args: parsed arguments from command line :return: True if checking passed, False - not passed """ if interpreter not in (NODEJS, PYTHON): return if as_from_root and any(( _args['create'], _args['read-config'], _args['save-config'], _args['install-modules'], _args['uninstall-modules'], _args['stop'], _args['restart'], _args['start'], _args['destroy'], _args['run-script'], )) and not (_args['--user'] or _args['--domain']): raise SchemaError(None, 'Domain or user argument is mandatory while calling selector under root') if args["--interpreter"] == PYTHON and args['--entry-point'] and not args['--startup-file']: raise SchemaError(None, '--entry-point option is requires --startup-file option for interpreter python') if args["--app-mode"] and args["--interpreter"] != NODEJS: raise SchemaError(None, '--app-mode option is requires only for interpreter nodejs') if args["--entry-point"] and args["--interpreter"] != PYTHON: raise SchemaError(None, '--entry-point option is requires only for interpreter python') try: args = s.validate(args) except SchemaError as e: return False, str(e) if not args['--json'] and not args['import-applications']: return False, "use --json option, other modes currently unsupported" if interpreter is None or interpreter in (PHP, ): args["--interpreter"] = PHP selector_status = False elif interpreter in (RUBY,): msg = 'ruby interpreter currently unsupported. Use selectorctl instead' return False, msg elif interpreter in (PYTHON, NODEJS): lib = CloudlinuxSelectorLib(args["--interpreter"]) selector_status = list(lib.get_selector_status().values())[0] try: _ensure_command_allowed(interpreter, args, as_from_root, selector_status) _check_users_part_cli(args) except SchemaError as e: return False, str(e) return True, args