mirror of
https://github.com/YunoHost/moulinette.git
synced 2024-09-03 20:06:31 +02:00
Merge branch 'dev' of https://github.com/jeromelebleu/moulinette into dev
This commit is contained in:
commit
c1981ce067
4 changed files with 561 additions and 183 deletions
16
README.md
16
README.md
|
@ -57,10 +57,18 @@ Specifications
|
||||||
|
|
||||||
### Monitoring
|
### Monitoring
|
||||||
|
|
||||||
yunohost monitor info [-h] [-u] [-d] [-p] [-c] [-m] [-i]
|
yunohost monitor disk [-h] [-m MOUNTPOINT] [-t] [-f] [-H]
|
||||||
yunohost monitor process [-h] [-e PROCESS] [-d PROCESS]
|
yunohost monitor network [-h] [-u] [-i] [-H]
|
||||||
[--stop PROCESS] [-c PORT] [-i]
|
yunohost monitor system [-h] [-m] [-u] [-i] [-p] [-c] [-H]
|
||||||
[--start PROCESS]
|
|
||||||
|
|
||||||
|
### Services
|
||||||
|
|
||||||
|
yunohost service status [-h] [NAME [NAME ...]]
|
||||||
|
yunohost service start [-h] NAME [NAME ...]
|
||||||
|
yunohost service stop [-h] NAME [NAME ...]
|
||||||
|
yunohost service enable [-h] NAME [NAME ...]
|
||||||
|
yunohost service disable [-h] NAME [NAME ...]
|
||||||
|
|
||||||
|
|
||||||
### Tools
|
### Tools
|
||||||
|
|
178
action_map.yml
178
action_map.yml
|
@ -425,68 +425,148 @@ backup:
|
||||||
# Monitor #
|
# Monitor #
|
||||||
#############################
|
#############################
|
||||||
monitor:
|
monitor:
|
||||||
category_help: Monitoring functions
|
category_help: Monitor the server
|
||||||
actions:
|
actions:
|
||||||
|
|
||||||
### monitor_info()
|
### monitor_disk()
|
||||||
info:
|
disk:
|
||||||
action_help: Check System
|
action_help: Monitor disk space and usage
|
||||||
|
arguments:
|
||||||
|
-f:
|
||||||
|
full: --filesystem
|
||||||
|
help: Show filesystem disk space
|
||||||
|
action: append_const
|
||||||
|
const: filesystem
|
||||||
|
dest: units
|
||||||
|
-t:
|
||||||
|
full: --io
|
||||||
|
help: Show I/O throughput
|
||||||
|
action: append_const
|
||||||
|
const: io
|
||||||
|
dest: units
|
||||||
|
-m:
|
||||||
|
full: --mountpoint
|
||||||
|
help: Monitor only the device mounted on MOUNTPOINT
|
||||||
|
action: store
|
||||||
|
-H:
|
||||||
|
full: --human-readable
|
||||||
|
help: Print sizes in human readable format
|
||||||
|
action: store_true
|
||||||
|
|
||||||
|
### monitor_network()
|
||||||
|
network:
|
||||||
|
action_help: Monitor network interfaces
|
||||||
|
arguments:
|
||||||
|
-u:
|
||||||
|
full: --usage
|
||||||
|
help: Show interfaces bit rates
|
||||||
|
action: append_const
|
||||||
|
const: usage
|
||||||
|
dest: units
|
||||||
|
-i:
|
||||||
|
full: --infos
|
||||||
|
help: Show network informations
|
||||||
|
action: append_const
|
||||||
|
const: infos
|
||||||
|
dest: units
|
||||||
|
-H:
|
||||||
|
full: --human-readable
|
||||||
|
help: Print sizes in human readable format
|
||||||
|
action: store_true
|
||||||
|
|
||||||
|
### monitor_system()
|
||||||
|
system:
|
||||||
|
action_help: Monitor system informations and usage
|
||||||
arguments:
|
arguments:
|
||||||
-m:
|
-m:
|
||||||
full: --memory
|
full: --memory
|
||||||
help: Check Memory
|
help: Show memory usage
|
||||||
action: store_true
|
action: append_const
|
||||||
-s:
|
const: memory
|
||||||
full: --swap
|
dest: units
|
||||||
help: Check Swap
|
|
||||||
action: store_true
|
|
||||||
-c:
|
-c:
|
||||||
full: --cpu
|
full: --cpu
|
||||||
help: Check CPU
|
help: Show CPU usage and load
|
||||||
action: store_true
|
action: append_const
|
||||||
-d:
|
const: cpu
|
||||||
full: --disk
|
dest: units
|
||||||
help: Check Disk
|
-p:
|
||||||
action: store_true
|
full: --process
|
||||||
-i:
|
help: Show processes summary
|
||||||
full: --ifconfig
|
action: append_const
|
||||||
help: Show Ip and MAC Adress
|
const: process
|
||||||
action: store_true
|
dest: units
|
||||||
-u:
|
-u:
|
||||||
full: --uptime
|
full: --uptime
|
||||||
help: Show Uptime
|
help: Show the system uptime
|
||||||
action: store_true
|
action: append_const
|
||||||
-p:
|
const: uptime
|
||||||
full: --public
|
dest: units
|
||||||
help: Show IP public
|
|
||||||
action: store_true
|
|
||||||
process:
|
|
||||||
action_help: Check Process
|
|
||||||
arguments:
|
|
||||||
-e:
|
|
||||||
full: --enable
|
|
||||||
help: Enable process
|
|
||||||
metavar: PROCESS
|
|
||||||
-d:
|
|
||||||
full: --disable
|
|
||||||
help: Disable process
|
|
||||||
metavar: PROCESS
|
|
||||||
--start:
|
|
||||||
help: Start process
|
|
||||||
metavar: PROCESS
|
|
||||||
--stop:
|
|
||||||
help: Stop process
|
|
||||||
metavar: PROCESS
|
|
||||||
-c:
|
|
||||||
full: --check
|
|
||||||
help: Check process
|
|
||||||
action: store_true
|
|
||||||
-i:
|
-i:
|
||||||
full: --info
|
full: --infos
|
||||||
help: Process info
|
help: Show system informations
|
||||||
|
action: append_const
|
||||||
|
const: infos
|
||||||
|
dest: units
|
||||||
|
-H:
|
||||||
|
full: --human-readable
|
||||||
|
help: Print sizes in human readable format
|
||||||
action: store_true
|
action: store_true
|
||||||
|
|
||||||
|
|
||||||
|
#############################
|
||||||
|
# Service #
|
||||||
|
#############################
|
||||||
|
service:
|
||||||
|
category_help: Manage services
|
||||||
|
actions:
|
||||||
|
|
||||||
|
### service_start()
|
||||||
|
start:
|
||||||
|
action_help: Start one or more services
|
||||||
|
arguments:
|
||||||
|
names:
|
||||||
|
help: Service name to start
|
||||||
|
nargs: +
|
||||||
|
metavar: NAME
|
||||||
|
|
||||||
|
### service_stop()
|
||||||
|
stop:
|
||||||
|
action_help: Stop one or more services
|
||||||
|
arguments:
|
||||||
|
names:
|
||||||
|
help: Service name to stop
|
||||||
|
nargs: +
|
||||||
|
metavar: NAME
|
||||||
|
|
||||||
|
### service_enable()
|
||||||
|
enable:
|
||||||
|
action_help: Enable one or more services
|
||||||
|
arguments:
|
||||||
|
names:
|
||||||
|
help: Service name to enable
|
||||||
|
nargs: +
|
||||||
|
metavar: NAME
|
||||||
|
|
||||||
|
### service_disable()
|
||||||
|
disable:
|
||||||
|
action_help: Disable one or more services
|
||||||
|
arguments:
|
||||||
|
names:
|
||||||
|
help: Service name to disable
|
||||||
|
nargs: +
|
||||||
|
metavar: NAME
|
||||||
|
|
||||||
|
### service_status()
|
||||||
|
status:
|
||||||
|
action_help: Show status information about one or more services (all by default)
|
||||||
|
arguments:
|
||||||
|
names:
|
||||||
|
help: Service name to show
|
||||||
|
nargs: "*"
|
||||||
|
metavar: NAME
|
||||||
|
|
||||||
|
|
||||||
#############################
|
#############################
|
||||||
# Firewall #
|
# Firewall #
|
||||||
#############################
|
#############################
|
||||||
|
|
|
@ -23,154 +23,198 @@
|
||||||
|
|
||||||
Monitoring functions
|
Monitoring functions
|
||||||
"""
|
"""
|
||||||
import xmlrpclib
|
import re
|
||||||
import json
|
import json
|
||||||
import psutil
|
import psutil
|
||||||
|
import subprocess
|
||||||
|
import xmlrpclib
|
||||||
from urllib import urlopen
|
from urllib import urlopen
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from yunohost import YunoHostError, win_msg, colorize, validate, get_required_args
|
from yunohost import YunoHostError
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
try:
|
|
||||||
import yaml
|
|
||||||
except ImportError:
|
|
||||||
sys.stderr.write('Error: Yunohost CLI Require yaml lib\n')
|
|
||||||
sys.stderr.write('apt-get install python-yaml\n')
|
|
||||||
sys.exit(1)
|
|
||||||
import json
|
|
||||||
import socket
|
|
||||||
import fcntl
|
|
||||||
import struct
|
|
||||||
if not __debug__:
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
s = xmlrpclib.ServerProxy('http://127.0.0.1:61209')
|
glances_uri = 'http://127.0.0.1:61209'
|
||||||
|
|
||||||
def get_ip_address(ifname):
|
def monitor_disk(units=None, mountpoint=None, human_readable=False):
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
||||||
return socket.inet_ntoa(fcntl.ioctl(
|
|
||||||
s.fileno(),
|
|
||||||
0x8915, # SIOCGIFADDR
|
|
||||||
struct.pack('256s', ifname[:15])
|
|
||||||
)[20:24])
|
|
||||||
|
|
||||||
def bytes2human(n):
|
|
||||||
symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
|
|
||||||
prefix = {}
|
|
||||||
for i, s in enumerate(symbols):
|
|
||||||
prefix[s] = 1 << (i+1)*10
|
|
||||||
for s in reversed(symbols):
|
|
||||||
if n >= prefix[s]:
|
|
||||||
value = float(n) / prefix[s]
|
|
||||||
return '%.1f%s' % (value, s)
|
|
||||||
return "%sB" % n
|
|
||||||
|
|
||||||
def process_enable(args):
|
|
||||||
output = subprocess.Popen(['update-rc.d', args, 'defaults'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
|
||||||
if output.wait() == 0:
|
|
||||||
return process_start(args)
|
|
||||||
return resultat
|
|
||||||
else:
|
|
||||||
raise YunoHostError(1, 'Enable : ' + args.title() + " " + _("failure"))
|
|
||||||
|
|
||||||
def process_disable(args):
|
|
||||||
output = subprocess.Popen(['update-rc.d', args, 'remove'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
|
||||||
if output.wait() == 0:
|
|
||||||
return process_stop(args)
|
|
||||||
return resultat
|
|
||||||
else:
|
|
||||||
raise YunoHostError(1, 'Disable : ' + args.title() + " " + _("failure"))
|
|
||||||
|
|
||||||
def process_start(args):
|
|
||||||
output = subprocess.Popen(['service', args, 'start'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
|
||||||
if output.wait() == 0:
|
|
||||||
return { 'Start' : args.title() }
|
|
||||||
else:
|
|
||||||
raise YunoHostError(1, 'Start : ' + args.title() + " " + _("failure"))
|
|
||||||
|
|
||||||
def process_stop(args):
|
|
||||||
output = subprocess.Popen(['service', args, 'stop'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
|
||||||
if output.wait() == 0:
|
|
||||||
return { 'Stop' : args.title() }
|
|
||||||
else:
|
|
||||||
raise YunoHostError(1, 'Stop : ' + args.title() + " " + _("failure"))
|
|
||||||
|
|
||||||
def process_check(args):
|
|
||||||
with open('process.yml', 'r') as f:
|
|
||||||
processes = yaml.load(f)
|
|
||||||
|
|
||||||
result = {}
|
|
||||||
for process, commands in processes.items():
|
|
||||||
if commands['status'] == 'service':
|
|
||||||
cmd = "service " + process + " status"
|
|
||||||
else:
|
|
||||||
cmd = commands['status']
|
|
||||||
|
|
||||||
if os.system(cmd + " > /dev/null 2>&1") == 0:
|
|
||||||
result.update({ process : _('Running') })
|
|
||||||
else:
|
|
||||||
result.update({ process : _('Down') })
|
|
||||||
|
|
||||||
return { 'Status' : result }
|
|
||||||
|
|
||||||
def monitor_info(memory=False, swap=False, cpu=False, disk=False, ifconfig=False, uptime=False, public=False):
|
|
||||||
"""
|
"""
|
||||||
Check System
|
Monitor disk space and usage
|
||||||
|
|
||||||
Keyword argument:
|
Keyword argument:
|
||||||
memory -- Check Memory
|
units -- Unit(s) to monitor
|
||||||
ifconfig -- Show Ip and MAC Adress
|
mountpoint -- Device mountpoint
|
||||||
disk -- Check Disk
|
human_readable -- Print sizes in human readable format
|
||||||
uptime -- Show Uptime
|
|
||||||
swap -- Check Swap
|
|
||||||
public -- Show IP public
|
|
||||||
cpu -- Check CPU
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if memory:
|
glances = _get_glances_api()
|
||||||
return json.loads(s.getMem())
|
result_dname = None
|
||||||
|
result = {}
|
||||||
|
|
||||||
if swap:
|
if units is None:
|
||||||
return json.loads(s.getMemSwap())
|
units = ['io', 'filesystem']
|
||||||
|
|
||||||
elif cpu:
|
# Get mounted block devices
|
||||||
return json.loads(s.getLoad())
|
devices = {}
|
||||||
|
output = subprocess.check_output('lsblk -o NAME,MOUNTPOINT -l -n'.split())
|
||||||
|
for d in output.split('\n'):
|
||||||
|
m = re.search(r'([a-z]+[0-9]+)[ ]+(\/\S*)', d) # Extract device name (1) and its mountpoint (2)
|
||||||
|
if m and (mountpoint is None or m.group(2) == mountpoint):
|
||||||
|
(dn, dm) = (m.group(1), m.group(2))
|
||||||
|
devices[dn] = dm
|
||||||
|
result[dn] = {} if len(units) > 1 else []
|
||||||
|
result_dname = dn if mountpoint is not None else None
|
||||||
|
if len(devices) == 0:
|
||||||
|
raise YunoHostError(1, _("Unknown mountpoint '%s'") % mountpoint)
|
||||||
|
|
||||||
elif ifconfig:
|
# Retrieve monitoring for unit(s)
|
||||||
result = {}
|
for u in units:
|
||||||
for k, fs in enumerate(json.loads(s.getNetwork())):
|
if u == 'io':
|
||||||
interface = fs['interface_name']
|
for d in json.loads(glances.getDiskIO()):
|
||||||
if interface != "lo":
|
dname = d['disk_name']
|
||||||
ip = get_ip_address(str(interface))
|
if dname in devices.keys():
|
||||||
del fs['interface_name']
|
del d['disk_name']
|
||||||
result[ip] = fs
|
if len(units) > 1:
|
||||||
else:
|
result[dname][u] = d
|
||||||
del fs['interface_name']
|
else:
|
||||||
result[interface] = fs
|
d['mnt_point'] = devices[dname]
|
||||||
return result
|
result[dname] = d
|
||||||
|
elif u == 'filesystem':
|
||||||
|
for d in json.loads(glances.getFs()):
|
||||||
|
dmount = d['mnt_point']
|
||||||
|
for (dn, dm) in devices.items():
|
||||||
|
# TODO: Show non-block filesystems?
|
||||||
|
if dm != dmount:
|
||||||
|
continue
|
||||||
|
del d['device_name']
|
||||||
|
if human_readable:
|
||||||
|
for i in ['used', 'avail', 'size']:
|
||||||
|
d[i] = _binary_to_human(d[i]) + 'B'
|
||||||
|
if len(units) > 1:
|
||||||
|
result[dn][u] = d
|
||||||
|
else:
|
||||||
|
result[dn] = d
|
||||||
|
else:
|
||||||
|
raise YunoHostError(1, _("Unknown unit '%s'") % u)
|
||||||
|
|
||||||
elif disk:
|
if result_dname is not None:
|
||||||
result = {}
|
return result[result_dname]
|
||||||
for k, fs in enumerate(json.loads(s.getFs())):
|
return result
|
||||||
if fs['fs_type'] != 'tmpfs' and fs['fs_type'] != 'rpc_pipefs':
|
|
||||||
mnt_point = str(fs['mnt_point'])
|
|
||||||
del fs['mnt_point']
|
|
||||||
result[mnt_point] = fs
|
|
||||||
return result
|
|
||||||
|
|
||||||
elif uptime:
|
|
||||||
uptime_value = (str(datetime.now() - datetime.fromtimestamp(psutil.BOOT_TIME)).split('.')[0])
|
|
||||||
return { 'Uptime' : uptime_value }
|
|
||||||
|
|
||||||
elif public:
|
def monitor_network(units=None, human_readable=False):
|
||||||
try:
|
"""
|
||||||
ip = str(urlopen('http://ip.yunohost.org').read())
|
Monitor network interfaces
|
||||||
except:
|
|
||||||
raise YunoHostError(1, _("No connection") )
|
Keyword argument:
|
||||||
return { 'Public IP' : ip }
|
units -- Unit(s) to monitor
|
||||||
|
human_readable -- Print sizes in human readable format
|
||||||
|
|
||||||
|
"""
|
||||||
|
glances = _get_glances_api()
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
if units is None:
|
||||||
|
units = ['usage', 'infos']
|
||||||
|
|
||||||
|
# Get network devices and their addresses
|
||||||
|
devices = {}
|
||||||
|
output = subprocess.check_output('ip addr show'.split())
|
||||||
|
for d in re.split('^(?:[0-9]+: )', output, flags=re.MULTILINE):
|
||||||
|
d = re.sub('\n[ ]+', ' % ', d) # Replace new lines by %
|
||||||
|
m = re.match('([a-z]+[0-9]?): (.*)', d) # Extract device name (1) and its addresses (2)
|
||||||
|
if m:
|
||||||
|
devices[m.group(1)] = m.group(2)
|
||||||
|
|
||||||
|
# Retrieve monitoring for unit(s)
|
||||||
|
for u in units:
|
||||||
|
if u == 'usage':
|
||||||
|
result[u] = {}
|
||||||
|
for i in json.loads(glances.getNetwork()):
|
||||||
|
iname = i['interface_name']
|
||||||
|
if iname in devices.keys():
|
||||||
|
del i['interface_name']
|
||||||
|
if human_readable:
|
||||||
|
for k in i.keys():
|
||||||
|
if k != 'time_since_update':
|
||||||
|
i[k] = _binary_to_human(i[k]) + 'B'
|
||||||
|
result[u][iname] = i
|
||||||
|
elif u == 'infos':
|
||||||
|
try:
|
||||||
|
p_ip = str(urlopen('http://ip.yunohost.org').read())
|
||||||
|
except:
|
||||||
|
raise YunoHostError(1, _("Public IP resolution failed"))
|
||||||
|
|
||||||
|
l_ip = None
|
||||||
|
for name, addrs in devices.items():
|
||||||
|
if name == 'lo':
|
||||||
|
continue
|
||||||
|
if len(devices) == 2:
|
||||||
|
l_ip = _extract_inet(addrs)
|
||||||
|
else:
|
||||||
|
if l_ip is None:
|
||||||
|
l_ip = {}
|
||||||
|
l_ip[name] = _extract_inet(addrs)
|
||||||
|
|
||||||
|
result[u] = {
|
||||||
|
'public_ip': p_ip,
|
||||||
|
'local_ip': l_ip,
|
||||||
|
'gateway': 'TODO'
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
raise YunoHostError(1, _("Unknown unit '%s'") % u)
|
||||||
|
|
||||||
|
if len(units) == 1:
|
||||||
|
return result[units[0]]
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def monitor_system(units=None, human_readable=False):
|
||||||
|
"""
|
||||||
|
Monitor system informations and usage
|
||||||
|
|
||||||
|
Keyword argument:
|
||||||
|
units -- Unit(s) to monitor
|
||||||
|
human_readable -- Print sizes in human readable format
|
||||||
|
|
||||||
|
"""
|
||||||
|
glances = _get_glances_api()
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
if units is None:
|
||||||
|
units = ['memory', 'cpu', 'process', 'uptime', 'infos']
|
||||||
|
|
||||||
|
# Retrieve monitoring for unit(s)
|
||||||
|
for u in units:
|
||||||
|
if u == 'memory':
|
||||||
|
ram = json.loads(glances.getMem())
|
||||||
|
swap = json.loads(glances.getMemSwap())
|
||||||
|
if human_readable:
|
||||||
|
for i in ram.keys():
|
||||||
|
if i != 'percent':
|
||||||
|
ram[i] = _binary_to_human(ram[i]) + 'B'
|
||||||
|
for i in swap.keys():
|
||||||
|
if i != 'percent':
|
||||||
|
swap[i] = _binary_to_human(swap[i]) + 'B'
|
||||||
|
result[u] = {
|
||||||
|
'ram': ram,
|
||||||
|
'swap': swap
|
||||||
|
}
|
||||||
|
elif u == 'cpu':
|
||||||
|
result[u] = {
|
||||||
|
'load': json.loads(glances.getLoad()),
|
||||||
|
'usage': json.loads(glances.getCpu())
|
||||||
|
}
|
||||||
|
elif u == 'process':
|
||||||
|
result[u] = json.loads(glances.getProcessCount())
|
||||||
|
elif u == 'uptime':
|
||||||
|
result[u] = (str(datetime.now() - datetime.fromtimestamp(psutil.BOOT_TIME)).split('.')[0])
|
||||||
|
elif u == 'infos':
|
||||||
|
result[u] = json.loads(glances.getSystem())
|
||||||
|
else:
|
||||||
|
raise YunoHostError(1, _("Unknown unit '%s'") % u)
|
||||||
|
|
||||||
|
if len(units) == 1 and type(result[units[0]]) is not str:
|
||||||
|
return result[units[0]]
|
||||||
|
return result
|
||||||
|
|
||||||
else:
|
|
||||||
raise YunoHostError(1, _('No arguments provided'))
|
|
||||||
|
|
||||||
def monitor_process(enable=None, disable=None, start=None, stop=None, check=False, info=False):
|
def monitor_process(enable=None, disable=None, start=None, stop=None, check=False, info=False):
|
||||||
"""
|
"""
|
||||||
|
@ -197,3 +241,63 @@ def monitor_process(enable=None, disable=None, start=None, stop=None, check=Fals
|
||||||
return process_check(check)
|
return process_check(check)
|
||||||
elif info:
|
elif info:
|
||||||
return json.loads(s.getProcessCount())
|
return json.loads(s.getProcessCount())
|
||||||
|
|
||||||
|
|
||||||
|
def _get_glances_api():
|
||||||
|
"""
|
||||||
|
Retrieve Glances API running on the local server
|
||||||
|
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
p = xmlrpclib.ServerProxy(glances_uri)
|
||||||
|
p.system.methodHelp('getAll')
|
||||||
|
except (xmlrpclib.ProtocolError, IOError):
|
||||||
|
# TODO: Try to start Glances service
|
||||||
|
raise YunoHostError(1, _("Connection to Glances server failed"))
|
||||||
|
|
||||||
|
return p
|
||||||
|
|
||||||
|
|
||||||
|
def _extract_inet(string):
|
||||||
|
"""
|
||||||
|
Extract IP address (v4 or v6) from a string
|
||||||
|
|
||||||
|
Keyword argument:
|
||||||
|
string -- String to search in
|
||||||
|
|
||||||
|
"""
|
||||||
|
# TODO: Return IPv4 and IPv6?
|
||||||
|
ip4_prog = re.compile('((25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}/[0-9]{1,2})')
|
||||||
|
ip6_prog = re.compile('((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?/[0-9]{1,2})')
|
||||||
|
|
||||||
|
m = ip4_prog.search(string)
|
||||||
|
if m:
|
||||||
|
return m.group(1)
|
||||||
|
|
||||||
|
m = ip6_prog.search(string)
|
||||||
|
if m:
|
||||||
|
return m.group(1)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _binary_to_human(n, customary=False):
|
||||||
|
"""
|
||||||
|
Convert bytes or bits into human readable format with binary prefix
|
||||||
|
|
||||||
|
Keyword argument:
|
||||||
|
n -- Number to convert
|
||||||
|
customary -- Use customary symbol instead of IEC standard
|
||||||
|
|
||||||
|
"""
|
||||||
|
symbols = ('Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi')
|
||||||
|
if customary:
|
||||||
|
symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
|
||||||
|
prefix = {}
|
||||||
|
for i, s in enumerate(symbols):
|
||||||
|
prefix[s] = 1 << (i+1)*10
|
||||||
|
for s in reversed(symbols):
|
||||||
|
if n >= prefix[s]:
|
||||||
|
value = float(n) / prefix[s]
|
||||||
|
return '%.1f%s' % (value, s)
|
||||||
|
return "%s" % n
|
||||||
|
|
186
yunohost_service.py
Normal file
186
yunohost_service.py
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
""" License
|
||||||
|
|
||||||
|
Copyright (C) 2013 YunoHost
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program; if not, see http://www.gnu.org/licenses
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
""" yunohost_service.py
|
||||||
|
|
||||||
|
Manage services
|
||||||
|
"""
|
||||||
|
import yaml
|
||||||
|
import glob
|
||||||
|
import subprocess
|
||||||
|
import os.path
|
||||||
|
from yunohost import YunoHostError, win_msg
|
||||||
|
|
||||||
|
|
||||||
|
def service_start(names):
|
||||||
|
"""
|
||||||
|
Start one or more services
|
||||||
|
|
||||||
|
Keyword argument:
|
||||||
|
names -- Services name to start
|
||||||
|
|
||||||
|
"""
|
||||||
|
for name in names:
|
||||||
|
if _run_service_command('start', name):
|
||||||
|
win_msg(_("'%s' service started") % name)
|
||||||
|
else:
|
||||||
|
raise YunoHostError(1, _("Service starting failed for '%s'") % name)
|
||||||
|
|
||||||
|
|
||||||
|
def service_stop(names):
|
||||||
|
"""
|
||||||
|
Stop one or more services
|
||||||
|
|
||||||
|
Keyword argument:
|
||||||
|
name -- Services name to stop
|
||||||
|
|
||||||
|
"""
|
||||||
|
for name in names:
|
||||||
|
if _run_service_command('stop', name):
|
||||||
|
win_msg(_("'%s' service stopped") % name)
|
||||||
|
else:
|
||||||
|
raise YunoHostError(1, _("Service stopping failed for '%s'") % name)
|
||||||
|
|
||||||
|
|
||||||
|
def service_enable(names):
|
||||||
|
"""
|
||||||
|
Enable one or more services
|
||||||
|
|
||||||
|
Keyword argument:
|
||||||
|
names -- Services name to enable
|
||||||
|
|
||||||
|
"""
|
||||||
|
for name in names:
|
||||||
|
if _run_service_command('enable', name):
|
||||||
|
win_msg(_("'%s' service enabled") % name)
|
||||||
|
else:
|
||||||
|
raise YunoHostError(1, _("Service enabling failed for '%s'") % name)
|
||||||
|
|
||||||
|
|
||||||
|
def service_disable(names):
|
||||||
|
"""
|
||||||
|
Disable one or more services
|
||||||
|
|
||||||
|
Keyword argument:
|
||||||
|
names -- Services name to disable
|
||||||
|
|
||||||
|
"""
|
||||||
|
for name in names:
|
||||||
|
if _run_service_command('disable', name):
|
||||||
|
win_msg(_("'%s' service disabled") % name)
|
||||||
|
else:
|
||||||
|
raise YunoHostError(1, _("Service disabling failed for '%s'") % name)
|
||||||
|
|
||||||
|
|
||||||
|
def service_status(names=None):
|
||||||
|
"""
|
||||||
|
Show status information about one or more services (all by default)
|
||||||
|
|
||||||
|
Keyword argument:
|
||||||
|
names -- Services name to show
|
||||||
|
|
||||||
|
"""
|
||||||
|
services = _get_services()
|
||||||
|
check_names = True
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
if names is None or len(names) == 0:
|
||||||
|
names = services.keys()
|
||||||
|
check_names = False
|
||||||
|
|
||||||
|
for name in names:
|
||||||
|
if check_names and name not in services.keys():
|
||||||
|
raise YunoHostError(1, _("Unknown service '%s'") % name)
|
||||||
|
|
||||||
|
status = None
|
||||||
|
if services[name]['status'] == 'service':
|
||||||
|
status = 'service %s status' % name
|
||||||
|
else:
|
||||||
|
status = str(services[name]['status'])
|
||||||
|
|
||||||
|
runlevel = 5
|
||||||
|
if 'runlevel' in services[name].keys():
|
||||||
|
runlevel = int(services[name]['runlevel'])
|
||||||
|
|
||||||
|
result[name] = { 'status': 'unknown', 'loaded': 'unknown' }
|
||||||
|
|
||||||
|
# Retrieve service status
|
||||||
|
try:
|
||||||
|
ret = subprocess.check_output(status.split(), stderr=subprocess.STDOUT)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
# TODO: log error
|
||||||
|
result[name]['status'] = _("inactive")
|
||||||
|
else:
|
||||||
|
result[name]['status'] = _("running")
|
||||||
|
|
||||||
|
# Retrieve service loading
|
||||||
|
rc_path = glob.glob("/etc/rc%d.d/S[0-9][0-9]%s" % (runlevel, name))
|
||||||
|
if len(rc_path) == 1 and os.path.islink(rc_path[0]):
|
||||||
|
result[name]['loaded'] = _("enabled")
|
||||||
|
elif os.path.isfile("/etc/init.d/%s" % name):
|
||||||
|
result[name]['loaded'] = _("disabled")
|
||||||
|
else:
|
||||||
|
result[name]['loaded'] = _("not-found")
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _run_service_command(action, service):
|
||||||
|
"""
|
||||||
|
Run services management command (start, stop, enable, disable)
|
||||||
|
|
||||||
|
Keyword argument:
|
||||||
|
service -- Service name
|
||||||
|
action -- Action to perform
|
||||||
|
|
||||||
|
"""
|
||||||
|
if service not in _get_services().keys():
|
||||||
|
raise YunoHostError(1, _("Unknown service '%s'") % service)
|
||||||
|
|
||||||
|
cmd = None
|
||||||
|
if action in ['start', 'stop']:
|
||||||
|
cmd = 'service %s %s' % (service, action)
|
||||||
|
elif action in ['enable', 'disable']:
|
||||||
|
arg = 'defaults' if action == 'enable' else 'remove'
|
||||||
|
cmd = 'update-rc.d %s %s' % (service, arg)
|
||||||
|
else:
|
||||||
|
raise YunoHostError(1, _("Unknown action '%s'") % service)
|
||||||
|
|
||||||
|
try:
|
||||||
|
ret = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
# TODO: log error instead
|
||||||
|
if os.isatty(1):
|
||||||
|
err = e.output.rstrip()
|
||||||
|
print(_("'%s' has returned:\n%s") % (' '.join(e.cmd), err))
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _get_services():
|
||||||
|
"""
|
||||||
|
Get a dict of managed services with their parameters
|
||||||
|
|
||||||
|
"""
|
||||||
|
with open('process.yml', 'r') as f:
|
||||||
|
services = yaml.load(f)
|
||||||
|
return services
|
Loading…
Reference in a new issue