Mini Shell
#!/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
#
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)
Zerion Mini Shell 1.0