????
Current Path : /usr/sbin/ |
Current File : //usr/sbin/lvectl |
#!/opt/cloudlinux/venv/bin/python3 -bb # coding=utf-8 # # Copyright © Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2018 All Rights Reserved # # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT # from __future__ import division from __future__ import print_function from __future__ import absolute_import import getopt import logging import sys import pwd import syslog import os from typing import Tuple, Text # NOQA from clcommon.utils import is_root_or_exit, get_cl_version from cllimits_validator import LimitsValidator, ENTITY_USER, ENTITY_PACKAGE, ENTITY_RESELLER, ENTITY_DEFAULTS from cllimitslib_v2 import DEFAULTS from clveconfig import DEFAULT_PROVIDER, VE_CFG_PATH is_root_or_exit() # check here or imports will fail import clcommon from clcommon.clproc import NoSuchLvp, LIMIT_LVP_ID from clcommon.cpapi.cpapiexceptions import CPAPIException from clcommon.lib.cledition import skip_without_lve from cllvectl.log import get_synchronous_logger import lveapi import lvestat as LVEStat from lve_utils.sentry import init_lve_utils_sentry_client import lvectllib as lve_commands from lvectllib import _page_to_memory_or_bytes import cldetectlib as detect from lve_utils import PKG_VERSION skip_without_lve() logger = get_synchronous_logger('lvectl') DO_NOT_EXIT = 999 PRINT_FORMATS = {True: { 8: '{"ID":"%s","SPEED":"%s","CPU":"%s","PMEM":"%s","VMEM":"%s","EP":"%s","NPROC":"%s","IO":"%s","IOPS":"%s"}', 6: '{"ID":"%s","SPEED":"%s","CPU":"%s","PMEM":"%s","VMEM":"%s","EP":"%s","NPROC":"%s","IO":"%s"}', 4: '{"ID":"%s","SPEED":"%s","CPU":"%s","VMEM":"%s","EP":"%s","IO":"%s"}'}, False: { 8: "%8s%8s%8s%8s%8s%8s%8s%8s", 6: "%8s%8s%8s%8s%8s%8s%8s", 4: "%8s%8s%8s%8s%8s"}} PRINT_HEADERS = {8: ('ID', 'SPEED', 'PMEM', 'VMEM', 'EP', 'NPROC', 'IO', 'IOPS'), 6: ('ID', 'SPEED', 'PMEM', 'VMEM', 'EP', 'NPROC', 'IO'), 4: ('ID', 'SPEED', 'VMEM', 'EP', 'IO')} _WPOS_DAEMON_SIGHUP_FILE = '/var/lve/wpos_reload' def _wpos_reload(): """ Create flag file for force sighup WPOS daemon """ try: if os.path.exists('/etc/clwpos/clwpos.json'): open(_WPOS_DAEMON_SIGHUP_FILE, 'w').close() except (OSError, IOError,): pass def print_error(message, print_usage_flag=False): if lve_commands.JSON: lve_commands.json_format( lve_commands.MULTI_FORMAT, ['ERROR', message] ) else: err_message = "error: %s" % message sys.stderr.write("%s\n" % err_message) if print_usage_flag: print_usage() def print_error_and_exit(message, exit_code=-1, print_usage_flag=False): print_error(message, print_usage_flag) if exit_code != DO_NOT_EXIT: sys.exit(exit_code) # GET VERSION from /proc/lve/list lve_ver = clcommon.get_lve_version() if lve_ver[0] is None: print_error_and_exit(lve_ver[1], 1) LVE_VERSION = lve_ver[0] LVE_VERSION = max(key for key in PRINT_HEADERS.keys() if key <= LVE_VERSION) # use max supported version try: lve_commands.init(LVE_VERSION) except Exception as e: print_error_and_exit(e, 1) # Check if JSON output required or old format without iops command_prompt = sys.argv[:] for i, el in enumerate(sys.argv): if el in ('json', '--json'): lve_commands.set_json(True) lve_commands.set_bytes('--bytes' in sys.argv) command_prompt.pop(i) if '--bytes' in sys.argv: command_prompt.pop(command_prompt.index('--bytes')) continue if el in ('no-iops', '--no-iops'): # check no-iops key in command prompt and drop LVE_VERSION to 6 if this key founded and LVE_VERSION is 8 if LVE_VERSION == 8: lve_commands.NOIOPS = True # STUPID HACK. Remove with iops release command_prompt.pop(i) continue syslog.openlog('lve-utils') def print_usage(): print('lvectl version ' + PKG_VERSION) print('usage: lvectl command [veid] [options]') print('commands:') print('apply apply config settings to specified LVE') print('apply all apply config settings to all the LVEs') print( 'apply-many to apply LVE limits to multiple distinct LVEs (uids of users are read from stdin)') print('set set parameters for a LVE and/or create a LVE') print('set-reseller create a LVP (resellers) container move LVE there') print('set-reseller-default set default limits for users inside LVP') print('sync-map load/update reseller:user map for correct support resellers limits') print('set-user set parameters for a LVE and/or create a LVE using username instead of ID') print('list list loaded LVEs') print('list-reseller list loaded LVPs, --with-name for display reselers name') print('list-user list loaded LVEs, display username instead of user id') print('limits show limits for loaded LVEs') print('all-user-list show limits for loaded LVEs with packages info') print('delete delete LVE and set configuration for that LVE to defaults') print( 'remove-reseller delete LVP container and record in config, move LVE containers to host container') print('delete-user delete LVE and set configuration for that user to defaults') print('destroy destroy LVE (configuration file remains unchanged)') print('destroy all destroy all LVE (configuration file remains unchanged)') print( 'destroy-many to destroy LVE limits to multiple distinct LVEs (uids of users are read from stdin)') print('package-set set LVE parameters for a package') print('package-list list LVE parameters for packages') print('reseller-package-list list LVE parameters for resellers packages') print( 'all-package-list list LVE parameters for all packages (whether it is resseler package or not )') print('package-delete delete LVE parameters for a package') print( 'paneluserslimits [reseller] show current user\'s limits for control panel. Reseller name is optional parameter') print('paneluserlimits show current limits for one user-id of user in control panel') print('limit limit PID into specified LVE. Parameters PID LVE_ID') print('release release PID from LVE. Parameters PID') print('set-binary add binary to be run inside LVE on execution') print('del-binary remove binary from being run inside LVE on execution') print('list-binaries list all binaries to be run inside LVE on execution') print('load-binaries load binaries (used on startup) from config file') print('reload-binaries re-load list of binaries from config file') print('help (-h) show this message') print('version (-v) version number') print('lve-version lve version number') print('options:') print('--enters-count enable limit for enters count (by default disabled), use only with command "limit"') if "cl6" not in get_cl_version(): print('--io-and-memory enable limit for IO and memory (by default disabled), use only with command "limit"') print('--cpu=N limit CPU usage; (deprecated. Use --speed)') print('--speed=N% limit CPU usage in percentage; 100% is one core ') print('--speed=Nmhz\ghz limit CPU usage in mhz\ghz') print('--io=N define io limits (KB/s)') if LVE_VERSION > 4: print('--nproc=N limit number of processes') print('--pmem=N limit physical memory usage for aplications inside LVE') if LVE_VERSION > 6: print('--iops=N limit io operations per second') print('--mem=N mem alias for vmem (deprecated)') print('--vmem=N limit virtual memory for applications inside LVE') print('--maxEntryProcs=N limit number of entry processes') print('--save save configuration settings (use with set) (deprecated)') print('--save-all-parameters save all parameters even if they match with defaults settings') print('--json returns result of command json formatted') print('--bytes show all limits in bytes. Works only with --json') print('--unlimited set all limits to unlimited') print( '--reseller specify reseller name who owns the package/uid; use with package-set/package-delete/set command') print('--skip-custom skip calling custom script inside lvectl') print("""--default=A,B,C set limits to default value (will delete lve first) available limits are either from %s or 'all' to reset all limits""" % ( "cpu, io, mem/vmem, ep/maxEntryProcs, nproc, pmem" if LVE_VERSION > 4 else "cpu, io, mem/vmem, ep/maxEntryProcs, nproc, pmem, iops" if LVE_VERSION > 6 else "cpu, io, mem/vmem, ep/maxEntryProcs")) print( '--save-username save username in the config file. This parameter is used in conjunction with set-user') print(f'--skip-update-cfg skip updating LVE parameters in {VE_CFG_PATH} (use with set)') print('') def validate_options(options): opts = {'ncpu', 'speed', 'cpu', 'io', 'mem', 'vmem', 'ep', 'maxEntryProcs'} if LVE_VERSION > 4: opts.update(['nproc', 'pmem']) if LVE_VERSION > 6: opts.update(['iops']) if len(options) == 1 and "all" in options: options = opts # check all options are valid if len(set(options) - opts) > 0: print_error_and_exit( "%s are not available options.\n\navailable options are:\n%s" % ( ', '.join(set(options) - opts), '\n'.join(opts)) ) # map options to set_data keys opts_map = {'ncpu': 'ncpu', 'speed': 'cpu', 'cpu': 'cpu', 'io': 'io', 'mem': 'mem', 'vmem': 'mem', 'ep': 'ep', 'maxEntryProcs': 'ep', 'nproc': 'nproc', 'pmem': 'pmem', 'iops': 'iops'} return set([opts_map[k] for k in options]) def invalid_option(o, a): print('Invalid value for option %s: %s' % (o, a)) print_usage() sys.exit(1) def id_to_name(ve_id, display_user): if ve_id == 0: return 'default' elif ve_id == LIMIT_LVP_ID: return 'limit' if display_user: try: return pwd.getpwuid(ve_id).pw_name except KeyError: pass return str(ve_id) def get_line_data(line, stats, display_user, with_reseller_name=False, prefix=''): ID = id_to_name(line, display_user) if with_reseller_name and ID.isdigit(): # for show reseller name with id ID += ':' + (lve_commands.lve.map.get_reseller_name(int(ID)) or 'N/A') # N/A if can't find lvp_id reseller name ID = prefix + ID data = () stats_line = stats[line] # type: lvestat.LVEStat if lve_commands.JSON: if lve_commands.NOIOPS and LVE_VERSION == 8: data = (ID, stats_line.cpu, lve_commands.speed_to_old_cpu(stats_line.cpu), _page_to_memory_or_bytes(stats_line.lmemphy), _page_to_memory_or_bytes(stats_line.lmem), stats_line.lep, stats_line.lnproc, stats_line.io) elif LVE_VERSION == 8: data = (ID, stats_line.cpu, lve_commands.speed_to_old_cpu(stats_line.cpu), _page_to_memory_or_bytes(stats_line.lmemphy), _page_to_memory_or_bytes(stats_line.lmem), stats_line.lep, stats_line.lnproc, stats_line.io, stats_line.liops) elif LVE_VERSION == 6: data = (ID, stats_line.cpu, lve_commands.speed_to_old_cpu(stats_line.cpu), _page_to_memory_or_bytes(stats_line.lmemphy), _page_to_memory_or_bytes(stats_line.lmem), stats_line.lep, stats_line.lnproc, stats_line.io) elif LVE_VERSION == 4: data = (ID, stats_line.cpu, lve_commands.speed_to_old_cpu(stats_line.cpu), _page_to_memory_or_bytes(stats_line.lmem), stats_line.lep, stats_line.io) else: if lve_commands.NOIOPS and LVE_VERSION == 8: data = (ID, stats_line.cpu, _page_to_memory_or_bytes(stats_line.lmemphy), _page_to_memory_or_bytes(stats_line.lmem), stats_line.lep, stats_line.lnproc, stats_line.io) elif LVE_VERSION == 8: data = (ID, stats_line.cpu, _page_to_memory_or_bytes(stats_line.lmemphy), _page_to_memory_or_bytes(stats_line.lmem), stats_line.lep, stats_line.lnproc, stats_line.io, stats_line.liops) elif LVE_VERSION == 6: data = (ID, stats_line.cpu, _page_to_memory_or_bytes(stats_line.lmemphy), _page_to_memory_or_bytes(stats_line.lmem), stats_line.lep, stats_line.lnproc, stats_line.io) elif LVE_VERSION == 4: data = (ID, stats_line.cpu, _page_to_memory_or_bytes(stats_line.lmem), stats_line.lep, stats_line.io) return data def limits_print(ve_id, display_user=False, lvp=False, with_reseller_name=False): if lvp: if ve_id == 'all': stats = parseLVPList() else: try: stats = parseLVEList(ve_id) except IOError: # if /proc/lve/resellers/lvp{ve_id}/list no present stats = dict() else: stats = dict() if lve_commands.lve.reseller_limit_supported(): for lvp_id_ in parseLVPList(): # scan all /proc/lve/resellers/lvp{ID}/list stats.update(parseLVEList(lvp_id_, ignore_id=LIMIT_LVP_ID)) stats.update(parseLVEList()) if lve_commands.NOIOPS and LVE_VERSION == 8: out_format = PRINT_FORMATS[lve_commands.JSON][6] else: out_format = PRINT_FORMATS[lve_commands.JSON][LVE_VERSION] if lve_commands.JSON: result = '{"data":[' separator = "," else: if lve_commands.NOIOPS and LVE_VERSION == 8: result = out_format % PRINT_HEADERS[6] + "\n" else: result = out_format % PRINT_HEADERS[LVE_VERSION] + "\n" separator = "\n" if ve_id == 'all' or lvp: result += separator.join( (out_format % get_line_data(line, stats, display_user, with_reseller_name=with_reseller_name) for line in stats)) else: for line in stats: if line == ve_id: result += out_format % get_line_data(line, stats, display_user) if lve_commands.JSON: result += ']}' else: result += separator try: print(result) except IOError: pass def _parse_lve_lines(lines, id_=None, ignore_id=None): stats = {} for line in lines: stat = LVEStat.LVEStat(line, lve_ver[0]) if id_ is not None and stat.id != id_: # filter by id if need continue if ignore_id is not None and stat.id == ignore_id: continue if (lve_ver[0] < 8): cpu_data = lve_commands.CPUINFO_DATA stat.cpu = stat.cpu * cpu_data[0] # cpu_data[0] - Num_core elif (lve_ver[0] >= 8): stat.cpu = stat.cpu // 100 stats[stat.id] = stat return stats def parseLVEList(lvp_id=0, id_=None, ignore_id=None): with open(lve_commands.lve.proc.get_list_path(lvp_id=lvp_id)) as lines: lines.readline() return _parse_lve_lines(lines, id_=id_, ignore_id=ignore_id) def parseLVPList(): # Remove from LVE all resellers, wich absent in panel lve_commands.remove_absent_resellers() stats = {} for lvp_id in lve_commands.lve.proc.lvp_id_list(): try: stats[lvp_id] = parseLVEList(lvp_id=lvp_id, id_=LIMIT_LVP_ID)[LIMIT_LVP_ID] except KeyError: pass return stats def delete_lve(a, lvp_id=0): if not str(a).isdigit(): print_error_and_exit("LVE id must be number") if delete_lve_int(int(a)): return print_error_and_exit("Invalid LVE id") def send_json_ok(): if lve_commands.JSON: lve_commands.json_format(lve_commands.SINGLE_FORMAT, ['OK']) def delete_lve_int(lve_id): if lve_id > 0: lve_commands.lve_delete(lve_id) send_json_ok() return True def delete_lve_by_name(a): try: if delete_lve_int(pwd.getpwnam(a).pw_uid): return except KeyError: pass print_error_and_exit("invalid username given") def convert_to_int_or_exit(val, error_message, exit_code=-1): try: return int(val) except ValueError: print_error_and_exit(error_message, exit_code) def parse_int_param(el, set_data, param_name, min_val, set_limits, max_val=sys.maxsize, alias=None): if not alias: alias = param_name try: set_data[param_name] = convert_to_int_or_exit(el.split('--' + alias + '=')[1], 'Non integer %s limit provided' % alias) if max_val >= set_data[param_name] >= min_val: set_limits.add(param_name) return True else: print_error_and_exit("%s limit is out of range" % alias) except IndexError: pass return False def parse_set_data(args, set_data): args.pop(0) args.pop(0) args2 = [] if len(args) > 0 and not args[0].startswith("--"): raise Exception("Wrong args") skip_next = False args_length = len(args) for idx, el in enumerate(args): # used current value as value for previous key if skip_next: skip_next = False continue if el.startswith("--"): # --key=value format if el.find("=") > 0: args2.append(el) elif idx < (args_length - 1): # next element is key again if (args[idx + 1]).startswith("--"): args2.append(el) # either value else: args2.append(el + "=" + args[idx + 1]) skip_next = True # no more elements, so it is key elif idx == args_length - 1: args2.append(el) args = args2 set_limits = set([]) set_options = [set(['default']), set(['unlimited']), set(['cpu', 'speed', 'ncpu', 'vmem', 'mem', 'pmem', 'io', 'maxEntryProcs', 'ep', 'nproc', 'iops'])] for el in args: parsed = False if el.startswith('--'): if el.startswith('--cpu'): print('Warning: --cpu option had been deprecated, use --speed instead') if 'speed' in set_limits: print_error_and_exit('Error: used both cpu and speed limit.') parsed = parsed or parse_int_param(el, set_data, 'cpu', 1, set_limits, max_val=100) if el.startswith('--speed'): if 'cpu' in set_limits: print_error_and_exit('Error: used both cpu and speed limit.') speed = el.split('--speed=')[1] speedlimit = lve_commands.convert_from_speed(speed) if speedlimit is None: print_error_and_exit('Speed limit error', 1, 1) parsed = False else: parsed = True set_data['cpu'] = speed set_limits.add('speed') parsed = parsed or parse_int_param(el, set_data, 'ncpu', 0, set_limits) if el.startswith('--mem') or el.startswith('--vmem'): set_data['mem'] = clcommon.memory_to_page(el.split('=')[1]) if set_data['mem'] == None: print_error_and_exit("Invalid vmem value") parsed = parsed or True set_limits.add('mem') parsed = parsed or parse_int_param(el, set_data, 'io', 0, set_limits) parsed = parsed or parse_int_param(el, set_data, 'ep', 0, set_limits) parsed = parsed or parse_int_param(el, set_data, 'ep', 0, set_limits, alias='maxEntryProcs') parsed = parsed or parse_int_param(el, set_data, 'nproc', 0, set_limits) if el.startswith('--pmem'): set_data['pmem'] = clcommon.memory_to_page(el.split('=')[1]) if set_data['pmem'] is None: print_error_and_exit("Invalid pmem value") parsed = parsed or True set_limits.add('pmem') parsed = parsed or parse_int_param(el, set_data, 'iops', 0, set_limits) if el == '--save': print_error('--save option had been deprecated') parsed = True if el == '--save-all-parameters': set_data['save'] = True parsed = True if el == '--unlimited': set_data['cpu'] = 100 set_data['ncpu'] = 0 set_data['mem'] = 0 set_data['io'] = 0 set_data['ep'] = 0 set_data['pmem'] = 0 set_data['nproc'] = 0 set_data['iops'] = 0 set_limits.add('unlimited') parsed = True if el.startswith('--default='): if set_data['ve_id'] == 0: print_error_and_exit("Can not reset default ve to default") opts_to_default = set([p for p in el.split('=')[1].split(',') if p != '']) set_data['set-default'] = validate_options(opts_to_default) set_limits.add('default') parsed = True if el.startswith('--reseller='): reseller_name = el.split("=")[1] set_data['reseller_name'] = reseller_name parsed = True # LU-400 if el == '--skip-custom': parsed = True if el == '--skip-update-cfg': set_data['skip-update-cfg'] = True parsed = True else: print_error_and_exit("wrong arguments for command: set", print_usage_flag=True) if not parsed: print_error_and_exit("unrecognized option or bad limit given %s" % el) if sum(bool(set_limits.intersection(s)) for s in set_options) > 1: print_error_and_exit("can not combine options: %s" % ', '.join(set_limits)) def parse_reseller(reseller_id): # type: (Text) -> Tuple[Text, int] """ Try to obtain reseller name and LVP id from given info :param reseller_id: reseller name or LVP id """ def _lvp_id_to_reseller_name(_lvp_id): # type: (int) -> Optional[Text] if _lvp_id <= 0: print_error_and_exit('Incorrect user id {}'.format(reseller_id)) lve_commands.get_XML_cfg() reseller_name = lve_commands.lve.map.get_reseller_name(_lvp_id) return reseller_name def _reseller_name_to_lvp_id(name): # type: (Text) -> Optional[int] lve_commands.get_XML_cfg() _lvp_id = lve_commands.lve.map.get_reseller_id(name) return _lvp_id lvp_id = None reseller_name = None try: lvp_id = int(reseller_id) except ValueError: reseller_name = reseller_id lvp_id = _reseller_name_to_lvp_id(reseller_name) else: reseller_name = _lvp_id_to_reseller_name(lvp_id) if reseller_name is None or lvp_id is None: print_error_and_exit( "{} is neither an existing reseller's name nor an LVE id".format(reseller_id) ) return lvp_id, reseller_name def process_lve_set(args, o): # variable lvp_id using for identificate operations with lve top container; # None - operations with default lve container; # list[lve_id1, lve_id2, ..., lveid_n] - operations with lve top container included simple lve containers id lvp_id = 0 # args example set limitt to uid: # args: ['set', '1023', '--reseller=res', '--iops=2222'] # o == 'set' if len(args) == 1: print_error_and_exit('No LVE ID provided') else: set_data = {} entity_type = None entity_id = None if o in ('set',): if args[1] == 'default': set_data['ve_id'] = 0 entity_type = ENTITY_DEFAULTS entity_id = DEFAULTS else: set_data['ve_id'] = convert_to_int_or_exit(args[1], "LVE ID must be numeric") entity_type = ENTITY_USER if set_data['ve_id'] != 0 else ENTITY_DEFAULTS entity_id = set_data['ve_id'] if set_data['ve_id'] != 0 else DEFAULTS elif o == 'set-reseller-default': set_data['ve_id'] = 0 lve_commands.get_XML_cfg() # load config or load reseller_name:reseller_id map lvp_id, set_data['user'] = parse_reseller(args[1]) if not lve_commands.lve.proc.exist_lvp(lvp_id): # We can not set up defaults for non-existing reseller container print_error_and_exit('LVP container does not exist', 1) entity_type = ENTITY_DEFAULTS entity_id = set_data['user'] elif o == 'set-reseller': # TODO: LU-952 if args[1] == '--all': # for anable lvp containers all resellers lvp_id = list() lve_commands.get_XML_cfg() # load config or load reseller_name:reseller_id map for reseller_name in lve_commands.lve.map.resellers(): lvp_id.append((reseller_name, lve_commands.lve.map.get_reseller_id(reseller_name))) else: lvp_id, set_data['user'] = parse_reseller(args[1]) set_data['ve_id'] = lvp_id entity_type = ENTITY_RESELLER entity_id = set_data['user'] else: if '--save-username' in args: set_data['save-username'] = True args.remove('--save-username') try: set_data['ve_id'] = pwd.getpwnam(args[1]).pw_uid except KeyError: print_error_and_exit("Invalid user name") entity_type = ENTITY_USER entity_id = set_data['ve_id'] # initializing 'save' flag. # then it will be set True in parse_set_data if "--save-all-parameters" argument is given # LU-574 # Force to save the limits for reseller (not for user with the same name, but for reseller as virtual entity) set_data['save'] = True if o == 'set-reseller' else False parse_set_data(args, set_data) # TODO: LU-952 if '--all' not in args: # Validation of settable limits. LU-919 limits_validator = LimitsValidator() result, messages = limits_validator.validate_input_limits( entity_type, entity_id, set_data ) if not result: print_error_and_exit( 'You\'re trying to set invalid LVE limits. {}'.format(' '.join(messages)), ) if isinstance(lvp_id, list): # if lvp list use for many lvp for reseller_name, lvp_id_ in lvp_id: set_data_ = dict(set_data) set_data_.update({'user': reseller_name, 've_id': lvp_id_}) lve_commands.lve_set(set_data_, lvp_id=lvp_id_) else: # Set limits for user's LVE if not lve_commands.lve_set(set_data, lvp_id=lvp_id): # Error lve_id does not match reseller print_error_and_exit( "User id '%s' is not owned by '%s'" % ( set_data['ve_id'], set_data.get('reseller_name', 'root') ) ) send_json_ok() return set_data def process_lve_package_set(args, lve_command_func=lve_commands.package_set): if len(args) == 1: print_error_and_exit('No package ID provided') else: set_data = {'ve_id': args[1], 'save': True} parse_set_data(args, set_data) entity_id = set_data['ve_id'] reseller = set_data.get('reseller_name', DEFAULT_PROVIDER) limits_validator = LimitsValidator() result, messages = limits_validator.validate_input_limits( ENTITY_PACKAGE, entity_id, set_data, reseller=reseller ) if not result: print_error_and_exit( 'You\'re trying to set invalid LVE limits. {}'.format(' '.join(messages)), ) if 'reseller_name' in set_data: if not lve_commands.reseller_package_set(set_data): print_error_and_exit("Reseller '%s' does not have package '%s'" % (set_data['reseller_name'], set_data['ve_id'])) else: lve_command_func(set_data) send_json_ok() def check_support_reseller_limits(): """ Check support resellers limits If not enabled or not support exit end print diagnostic message """ # error code 38 - ENOSYS Function not implemented # check supported kernel if not lve_commands.lve.is_lve10(): print_error_and_exit( 'Please, update your LVE to 1.5.x to use this command', exit_code=38 ) # check supported clcommon panel_name = detect.getCPName() # check supported control panel if not lve_commands.lve.is_panel_supported(): print_error_and_exit( 'Reseller limits is not supported on "{}" control panel now'.format(panel_name), exit_code=38 ) def sync_map(): """ load/update reseller:user map :return: """ lve_commands.get_XML_cfg() lve_commands.lve.sync_map() lve_commands.remove_absent_users() lve_commands.remove_absent_resellers() def main(argv=None): opts = () args = () try: logger.info('Starting lvectl with arguments: %s', sys.argv) opts, args = getopt.getopt(argv or command_prompt[1:], 'vh:', ['help', 'version', 'apply=', 'list', 'list-reseller', 'list-user', 'limits=', 'all-user-list', 'destroy=', 'delete=', 'remove-reseller=', "delete-user=", 'set=', 'set-reseller=', 'set-user=', 'ubc', 'package-set=', 'package-set-ext=', 'package-delete=', 'package-list', 'reseller-package-list', 'all-package-list', 'sync-map', 'start', 'lve-version', 'destroy-many', 'apply-many', 'paneluserslimits', 'limit=', 'release=', 'set-binary', 'del-binary', 'list-binaries', 'load-binaries', 'reload-binaries', 'paneluserlimits', 'destroy-and-recreate-all']) except getopt.GetoptError: print_error_and_exit('unknown or missing command', 1, True) if len(opts) == 0 and len(args) == 0: print_error_and_exit('unknown or missing command', 1, True) # hack for using line like lvectl command argument if len(opts) == 0: opts = [] for i in range(0, len(args), 2): if i + 1 < len(args): opts.append((args[i], args[i + 1])) else: opts.append((args[i], '')) executed = False for command, arg in opts: arg: str if command in ('-v', '--version', 'version'): print(PKG_VERSION) sys.exit(0) if command in ('--lve-version', 'lve-version'): if lve_commands.JSON: lve_commands.json_format( lve_commands.MULTI_FORMAT, ['OK', LVE_VERSION] ) else: print(LVE_VERSION) sys.exit(0) if command in ('-h', '--help', 'help'): print_usage() sys.exit(0) if command in ('start', '--start'): executed = True lve_commands.get_XML_cfg() lve_commands.lve_start() if command in ('sync-map',): check_support_reseller_limits() sync_map() lve_commands.write_effective_cache() sys.exit(0) if command in ('set-binary', '--set-binary'): lve_commands.get_global_lock(True) lve_commands.set_binary(arg) send_json_ok() sys.exit(0) if command in ('del-binary', '--del-binary'): lve_commands.get_global_lock(True) lve_commands.del_binary(arg) send_json_ok() sys.exit(0) if command in ('list-binaries', '--list-binaries'): lve_commands.list_binaries() sys.exit(0) if command in ('load-binaries', '--load-binaries'): lve_commands.load_binaries() send_json_ok() sys.exit(0) if command in ('reload-binaries', '--reload-binaries'): lve_commands.reload_binaries() send_json_ok() sys.exit(0) if command in ('apply-many', '--apply-many'): executed = True users = sys.stdin.readlines() if len(users) == 0: print_error_and_exit('user list is empty') lve_commands.apply_many(users) # Cached effective limits will be written to file once per operation. lve_commands.write_effective_cache() if command in ('destroy-many', '--destroy-many'): executed = True users = sys.stdin.readlines() if len(users) == 0: print_error_and_exit('user list is empty') lve_commands.destroy_many(users) _wpos_reload() if command in ('apply', '--apply'): executed = True if len(arg) != 0: if arg == 'all': lve_commands.lve_apply_all() if lve_commands.lve.reseller_limit_supported(): lve_commands.lve.sync_map() lve_commands.write_effective_cache(reset=True) send_json_ok() sys.exit(0) else: lve_id = convert_to_int_or_exit(arg, 'Invalid LVE ID') if lve_id >= 0: lve_commands.get_XML_cfg() if lve_commands.lve.reseller_limit_supported(): lve_commands.get_XML_cfg(lvp_id=lve_commands.lve.lve2lvp(lve_id)) lve_commands.lve_apply(lve_id) if lve_commands.lve.reseller_limit_supported(): lve_commands.lve.sync_map() else: print_error_and_exit("Invalid LVE Id") lve_commands.write_effective_cache() send_json_ok() if command in ('limit', '--limit'): executed = True flags = lveapi.LVE_NO_UBC | lveapi.LVE_NO_MAXENTER supported_flags = { "enters-count": lveapi.LVE_NO_MAXENTER } if "cl6" not in get_cl_version(): supported_flags["io-and-memory"] = lveapi.LVE_NO_UBC flags_count = 0 for arg in args[1:]: if not arg.startswith("--"): break flag = arg[2:] if flag in supported_flags: flags &= ~supported_flags[flag] flags_count += 1 else: print_error_and_exit(f"No such flag: {arg}. Please, use only {list(supported_flags.keys())}.") try: PID = convert_to_int_or_exit(args[flags_count + 1], "PID must be numeric.") except IndexError: print_error_and_exit("You have to specify PID.") try: VE = convert_to_int_or_exit(args[flags_count + 2], "LVE ID must be numeric.") except IndexError: print_error_and_exit("You have to specify LVE ID.") lve_commands.limit_pid(VE, PID, flags) send_json_ok() if command in ('release', '--release'): executed = True PID = convert_to_int_or_exit(arg, 'PID must be numeric') lve_commands.release_pid(PID) send_json_ok() if command in ('list', '--list'): executed = True limits_print('all') if command in ('list-user', '--list-user'): executed = True limits_print('all', True) if command in ('paneluserslimits', '--paneluserslimits'): executed = True if len(arg) == 0: lve_commands.paneluserslimits() # LU-530 else: reseller = str(arg) lve_commands.paneluserslimits(reseller=reseller) if command in ('paneluserlimits', '--paneluserlimits'): executed = True if len(arg) == 0: print_error_and_exit('paneluserlimits takes USER ID of control panel') user_id = convert_to_int_or_exit(arg, "bad USER ID") if user_id >= 0: lve_commands.paneluserslimits(userid=user_id) else: print_error_and_exit("bad USER ID") if command in ('limits', '--limits'): executed = True if len(arg) == 0: print_error_and_exit("limits takes LVE ID or 'all' argument") if arg == 'default': arg = 0 if arg == 'all': limits_print(arg) sys.exit(0) lve_id = convert_to_int_or_exit(arg, "bad LVE ID") if lve_id >= 0: limits_print(lve_id) else: print_error_and_exit("bad LVE id") if command in ('list-reseller',): executed = True check_support_reseller_limits() if len(arg) == 0 or arg in ('--bytes',): limits_print('all', lvp=True) # print limits for all resellers elif '--with-name' == arg: lve_commands.get_XML_cfg() # for loading reseller_name<=>reseller_id map form ve.cfg limits_print('all', lvp=True, with_reseller_name=True) else: lvp_id, _ = parse_reseller(arg) limits_print(lvp_id, lvp=True) if command == 'destroy-and-recreate-all': # NOTE(vlebedev): This is a workaround/hack to avoid the two-step process of first destroying all lves # and only then recreating them all with proper limits. This proofed to be problematic # due to the fact that destroy (and possibly create/apply) might hang indefinitely and # the server will be left with limits already reset for all but not yet re-applied for # some due to lvectl transitive hanging. # Technically, this is an equivalent of `lvectl destroy all` and `lvectl apply all` # executed sequentially, but in a single command and this additionanl safety net. executed = True lve_commands.lve_destroy_and_recreate_all() if lve_commands.lve.reseller_limit_supported(): lve_commands.lve.sync_map() lve_commands.write_effective_cache(reset=True) _wpos_reload() if command in ('destroy', '--destroy'): executed = True if len(arg) == 0: print_error_and_exit('destroy takes 2 arguments') if arg == 'default' or arg == '0': print_error_and_exit('cannot destroy default LVE') if arg == 'all': lve_commands.lve_destroy('all') else: lve_id = convert_to_int_or_exit(arg, 'BAD LVE ID') if lve_id > 0: lve_commands.lve_destroy(int(arg)) else: print_error_and_exit("Bad LVE ID") _wpos_reload() if command in ('delete', '--delete', 'remove-reseller'): executed = True lve_commands.get_global_lock(True) if len(arg) == 0 or arg == 'all': print_error_and_exit("wrong arguments for --delete") if arg == '0' or arg == 'default': print_error_and_exit("cannot delete default LVE") if command == 'remove-reseller': check_support_reseller_limits() lvp_id, reseller_name = parse_reseller(arg) lve_commands.disable_reseller_limits(reseller_name=reseller_name, lvp_id=lvp_id) send_json_ok() else: delete_lve(arg) # Not resetting because not all effective limits would be calculated during this # lvectl run, and write_effective_cache with reset replaces the cache file data with # those specifically. lve_commands.write_effective_cache() if command in ('delete-user', '--delete-user'): executed = True lve_commands.get_global_lock(True) delete_lve_by_name(arg) if command in ('--set',): executed = True print_usage() if command in ('--ubc', 'ubc'): executed = True print('UBC option is no longer available. If you would like to disable virtual memory limit,' ' please use --vmem=0 option') if command in ('--package-set',): # not accepted with dashes executed = True print_usage() # LU-400 # call custom script for Endurance than we set/delete limits for user if command in ('set', 'set-user', 'delete', 'delete-user', 'package-set', 'package-set-ext', 'package-delete'): if '--skip-custom' not in args: lve_commands.call_endurance_custom_script(args=args) if command in ('set', 'set-user'): executed = True lve_commands.get_global_lock(True) lve_set_data = process_lve_set(args, command) # We want to keep the effective limit cache matched to the ve.cfg file, # so if ve.cfg is not updated, neither should the cache. # "skip-update-cfg" might not be in the dict, so we get() if not lve_set_data.get('skip-update-cfg', False): lve_commands.write_effective_cache() if command in ('set-reseller', 'set-reseller-default'): executed = True check_support_reseller_limits() lve_commands.get_global_lock(True) lve_set_data = process_lve_set(args, command) if not lve_set_data.get('skip-update-cfg', False): lve_commands.write_effective_cache() if command in ('package-set',): executed = True lve_commands.get_global_lock(True) process_lve_package_set(args) lve_commands.write_effective_cache() if command in ('package-set-ext',): executed = True lve_commands.get_global_lock(True) process_lve_package_set(args, lve_command_func=lve_commands.package_set_ext) lve_commands.write_effective_cache() if command in ('package-delete', '--package-delete'): executed = True lve_commands.get_global_lock(True) if len(arg) == 0: print_error_and_exit("wrong arguments for delete command") reseller = [el for el in args if el.startswith("--reseller=")] if len(reseller) == 1: lve_commands.reseller_plan_delete(arg, reseller[0].split("=")[1]) else: lve_commands.plan_delete(arg) # lve_apply_all is called under the hood, so it's OK to reset the cache file after lve_commands.write_effective_cache(reset=True) send_json_ok() if command in ('package-list', '--package-list'): executed = True lve_commands.get_packages_list() if command in ('all-package-list',): executed = True lve_commands.get_all_packages_list() if command in ('all-user-list',): executed = True lve_commands.all_users_limits() if command in ('reseller-package-list', '--reseller-package-list'): executed = True lve_commands.get_resellers_packages_list() if not executed: print_error_and_exit('unknown or missing command', exit_code=1, print_usage_flag=True) if __name__ == "__main__": init_lve_utils_sentry_client('lvectl') try: main() except (NoSuchLvp, lveapi.PyLveError, CPAPIException) as e: print_error_and_exit(str(e), exit_code=1)