Merge branch 'dev' of github.com:YunoHost/moulinette into dev

This commit is contained in:
Kload 2013-06-01 00:17:43 +02:00
commit 4ca2abfde6
10 changed files with 230 additions and 73 deletions

View file

@ -132,6 +132,7 @@ git checkout -b dev_beudbeud ``
git rebase origin/dev git rebase origin/dev
``` ```
Do your modifications, then : Do your modifications, then :
``` ```
git commit -am 'My commit message' git commit -am 'My commit message'

View file

@ -220,7 +220,6 @@ app:
-n: -n:
full: --name full: --name
help: Name of the list (default fapp) help: Name of the list (default fapp)
pattern: '^[a-z0-9_]+$'
### app_listlists() ### app_listlists()
listlists: listlists:
@ -491,6 +490,24 @@ firewall:
action: store_true action: store_true
### firewall_installupnp()
installupnp:
action_help: Add upnp cron
### firewall_removeupnp()
removeupnp:
action_help: Remove upnp cron
### firewall_stop()
stop:
action_help: Stop iptables and ip6tables
### firewall_checkupnp()
checkupnp:
action_help: check if UPNP is install or not (0 yes 1 no)
############################# #############################
# Tools # # Tools #
############################# #############################

View file

@ -1,6 +1,7 @@
UPNP: false
ipv4: ipv4:
TCP: [22, 25, 53, 80, 443, 5222, 5269, 5280] TCP: [22, 25, 53, 80, 443, 5222, 5269, 5280, 6767]
UDP: [] UDP: [53]
ipv6: ipv6:
TCP: [22] TCP: [22]
UDP: [] UDP: [53]

View file

@ -57,9 +57,9 @@ childs:
- sudoRole - sudoRole
- top - top
cn=www-data,ou=sudo: cn=yunohost-admin,ou=sudo:
cn: www-data cn: yunohost-admin
sudoUser: www-data sudoUser: yunohost-admin
sudoHost: ALL sudoHost: ALL
sudoCommand: /usr/bin/yunohost sudoCommand: /usr/bin/yunohost
sudoOption: "!authenticate" sudoOption: "!authenticate"

View file

@ -38,7 +38,7 @@ if not __debug__:
gettext.install('YunoHost') gettext.install('YunoHost')
try: try:
from yunohost import YunoHostError, YunoHostLDAP, str_to_func, colorize, pretty_print_dict, display_error, validate from yunohost import YunoHostError, YunoHostLDAP, str_to_func, colorize, pretty_print_dict, display_error, validate, win
except ImportError: except ImportError:
sys.stderr.write('Error: Yunohost CLI Require YunoHost lib\n') sys.stderr.write('Error: Yunohost CLI Require YunoHost lib\n')
sys.exit(1) sys.exit(1)
@ -202,15 +202,21 @@ def main():
#print(_("Not (yet) implemented function")) #print(_("Not (yet) implemented function"))
#return 1 #return 1
except YunoHostError, error: except YunoHostError, error:
display_error(error) display_error(error, json_print)
return error.code return error.code
else: else:
if result is None: if json_print or not os.isatty(1):
pass if result is None:
elif os.isatty(1) and not json_print: result = {}
if len(win) > 0:
result['success'] = []
for msg in win:
result['success'].append(msg)
print(json.dumps(result))
elif result is not None:
pretty_print_dict(result) pretty_print_dict(result)
else: else:
print(json.dumps(result)) pass
return 0 return 0

View file

@ -17,6 +17,7 @@ import string
if not __debug__: if not __debug__:
import traceback import traceback
win = []
lemon_tmp_conf = '/tmp/tmplemonconf' lemon_tmp_conf = '/tmp/tmplemonconf'
def random_password(length=8): def random_password(length=8):
@ -51,9 +52,11 @@ def pretty_print_dict(d, depth=0):
pretty_print_dict(v, depth+1) pretty_print_dict(v, depth+1)
elif isinstance(v, list): elif isinstance(v, list):
print((" ") * depth + ("%s: " % str(k))) print((" ") * depth + ("%s: " % str(k)))
for value in v: for key, value in enumerate(v):
if isinstance(value, tuple): if isinstance(value, tuple):
pretty_print_dict({value[0]: value[1]}, depth+1) pretty_print_dict({value[0]: value[1]}, depth+1)
elif isinstance(value, dict):
pretty_print_dict({key: value}, depth+1)
else: else:
print((" ") * (depth+1) + "- " +str(value)) print((" ") * (depth+1) + "- " +str(value))
else: else:
@ -87,8 +90,12 @@ def win_msg(astr):
astr -- Win message to display astr -- Win message to display
""" """
global win
if os.isatty(1): if os.isatty(1):
print('\n' + colorize(_("Success: "), 'green') + astr + '\n') print('\n' + colorize(_("Success: "), 'green') + astr + '\n')
else:
win.append(astr)
def str_to_func(astr): def str_to_func(astr):
@ -175,17 +182,17 @@ def get_required_args(args, required_args, password=False):
return args return args
def display_error(error): def display_error(error, json_print=False):
""" """
Nice error displaying Nice error displaying
""" """
if not __debug__ : if not __debug__ :
traceback.print_exc() traceback.print_exc()
if os.isatty(1): if os.isatty(1) and not json_print:
print('\n' + colorize(_("Error: "), 'red') + error.message) print('\n' + colorize(_("Error: "), 'red') + error.message)
else: else:
print(json.dumps({ 'error' : error.message })) print(json.dumps({ error.code : error.message }))
def lemon_configuration(conf_dict): def lemon_configuration(conf_dict):

View file

@ -56,8 +56,8 @@ def app_fetchlist(url=None, name=None):
except OSError: os.makedirs(repo_path) except OSError: os.makedirs(repo_path)
if not url: if not url:
url = 'http://fapp.yunohost.org/app/list/raw' url = 'http://app.yunohost.org/list.json'
name = "fapp" name = 'yunohost'
else: else:
if not name: raise YunoHostError(22, _("You must indicate a name for your custom list")) if not name: raise YunoHostError(22, _("You must indicate a name for your custom list"))
@ -316,10 +316,9 @@ def app_install(app, domain, path='/', label=None, mode='private'):
# Apache # # Apache #
########## ##########
a2_conf_lines = [ a2_conf_lines = [ 'Alias '+ path +' '+ app_final_path + manifest['launch_path'] ]
'Alias '+ path +' '+ app_final_path + manifest['launch_path'], if path != '/':
'Alias '+ path[:len(path)-1] +' '+ app_final_path + manifest['launch_path'] a2_conf_lines.append('Alias '+ path[:len(path)-1] +' '+ app_final_path + manifest['launch_path'])
]
if lvl(manifest, 'yunohost', 'webapp', 'language') and manifest['yunohost']['webapp']['language'] == 'php': if lvl(manifest, 'yunohost', 'webapp', 'language') and manifest['yunohost']['webapp']['language'] == 'php':
for line in open(a2_template_path +'/php.conf'): a2_conf_lines.append(line.rstrip()) for line in open(a2_template_path +'/php.conf'): a2_conf_lines.append(line.rstrip())
@ -573,7 +572,7 @@ def _install_app_dependencies(dep_dict):
""" """
if ('debian' in dep_dict) and (len(dep_dict['debian']) > 0): if ('debian' in dep_dict) and (len(dep_dict['debian']) > 0):
#os.system('apt-get update') #os.system('apt-get update')
if os.system('apt-get install "'+ '" "'.join(dep_dict['debian']) +'"') != 0: if os.system('apt-get install -y "'+ '" "'.join(dep_dict['debian']) +'"') != 0:
raise YunoHostError(1, _("Dependency installation failed: ") + dependency) raise YunoHostError(1, _("Dependency installation failed: ") + dependency)
# TODO: Install npm, pip, gem and pear dependencies # TODO: Install npm, pip, gem and pear dependencies

View file

@ -33,7 +33,7 @@ def firewall_allow(protocol=None, port=None, ipv6=None, upnp=False):
""" """
port = int(port) port = int(port)
if (upnp): if (upnp):
add_portmapping(protocol, upnp, ipv6) add_portmapping(protocol, upnp, ipv6,'a')
if 0 < port < 65536: if 0 < port < 65536:
if protocol == "Both": if protocol == "Both":
@ -108,27 +108,40 @@ def firewall_reload(upnp=False):
os.system ("iptables -P INPUT ACCEPT") os.system ("iptables -P INPUT ACCEPT")
os.system ("iptables -F") os.system ("iptables -F")
os.system ("iptables -X") os.system ("iptables -X")
os.system ("iptables -A INPUT -m state --state ESTABLISHED -j ACCEPT")
if 22 not in firewall['ipv4']['TCP']: if 22 not in firewall['ipv4']['TCP']:
update_yml(22, 'TCP', 'a', False) update_yml(22, 'TCP', 'a', False)
if(os.path.exists("/proc/net/if_inet6")):
os.system ("ip6tables -P INPUT ACCEPT") os.system ("ip6tables -P INPUT ACCEPT")
os.system ("ip6tables -F") os.system ("ip6tables -F")
os.system ("ip6tables -X") os.system ("ip6tables -X")
os.system ("ip6tables -A INPUT -m state --state ESTABLISHED -j ACCEPT")
if 22 not in firewall['ipv6']['TCP']: if 22 not in firewall['ipv6']['TCP']:
update_yml(22, 'TCP', 'a', False) update_yml(22, 'TCP', 'a', False)
if upnp:
remove_portmapping()
add_portmapping('TCP', upnp, False,'r');
add_portmapping('UDP', upnp, False,'r');
if(os.path.exists("/proc/net/if_inet6")):
add_portmapping('TCP', upnp, True,'r');
add_portmapping('UDP', upnp, True,'r');
add_portmapping('TCP', upnp, False); os.system ("iptables -A INPUT -i lo -j ACCEPT")
add_portmapping('UDP', upnp, False); os.system ("iptables -A INPUT -p icmp -j ACCEPT")
add_portmapping('TCP', upnp, True);
add_portmapping('UDP', upnp, True);
os.system ("iptables -P INPUT DROP") os.system ("iptables -P INPUT DROP")
os.system ("ip6tables -P INPUT DROP")
if(os.path.exists("/proc/net/if_inet6")):
os.system ("ip6tables -A INPUT -i lo -j ACCEPT")
os.system ("ip6tables -A INPUT -p icmp -j ACCEPT")
os.system ("ip6tables -P INPUT DROP")
os.system("service fail2ban restart")
win_msg(_("Firewall successfully reloaded")) win_msg(_("Firewall successfully reloaded"))
return firewall_list() return firewall_list()
@ -174,46 +187,156 @@ def update_yml(port=None, protocol=None, mode=None, ipv6=None):
yaml.dump(firewall, f) yaml.dump(firewall, f)
def add_portmapping(protocol=None, upnp=False, ipv6=None): def add_portmapping(protocol=None, upnp=False, ipv6=None,mode=None,):
""" """
Send a port mapping rules to igd device Send a port mapping rules to igd device
Keyword arguments: Keyword arguments:
protocol -- Protocol used protocol -- Protocol used
port -- Port to open upnp -- Boolean upnp
ipv6 -- Boolean ipv6
mode -- Add a rule (a) or reload all rules (r)
Return Return
None None
""" """
os.system ("iptables -P INPUT ACCEPT") if ipv6:
if upnp: os.system ("ip6tables -P INPUT ACCEPT")
upnp = miniupnpc.UPnP() else:
upnp.discoverdelay = 200 os.system ("iptables -P INPUT ACCEPT")
nbigd = upnp.discover()
if nbigd:
try:
upnp.selectigd()
except:
firewall_reload(False)
raise YunoHostError(167,_("No upnp devices found"))
else:
firewall_reload(False)
raise YunoHostError(22,_("Can't connect to the igd device"))
# list the redirections :
for i in xrange(100):
p = upnp.getgenericportmapping(i)
if p is None: break
upnp.deleteportmapping(p[0], p[1])
if upnp and mode=='a':
remove_portmapping()
if ipv6: ip = 'ipv6' if ipv6: ip = 'ipv6'
else: ip = 'ipv4' else: ip = 'ipv4'
with open('firewall.yml', 'r') as f: with open('firewall.yml', 'r') as f:
firewall = yaml.load(f) firewall = yaml.load(f)
for i,port in enumerate (firewall[ip][protocol]): for i,port in enumerate (firewall[ip][protocol]):
os.system ("iptables -A INPUT -p "+ protocol +" -i eth0 --dport "+ str(port) +" -j ACCEPT") if ipv6:
os.system ("ip6tables -A INPUT -p "+ protocol +" -i eth0 --dport "+ str(port) +" -j ACCEPT")
else:
os.system ("iptables -A INPUT -p "+ protocol +" -i eth0 --dport "+ str(port) +" -j ACCEPT")
if upnp: if upnp:
upnp.addportmapping(port, protocol, upnp.lanaddr, port, 'yunohost firewall : port %u' % port, '') upnpc = miniupnpc.UPnP()
upnpc.discoverdelay = 200
nbigd = upnpc.discover()
if nbigd:
upnpc.selectigd()
upnpc.addportmapping(port, protocol, upnpc.lanaddr, port, 'yunohost firewall : port %u' % port, '')
os.system ("iptables -P INPUT DROP") os.system ("iptables -P INPUT DROP")
def remove_portmapping():
"""
Remove all portmapping rules in the igd device
Keyword arguments:
None
Return
None
"""
upnp = miniupnpc.UPnP()
upnp.discoverdelay = 200
nbigd = upnp.discover()
if nbigd:
try:
upnp.selectigd()
except:
firewall_reload(False)
raise YunoHostError(167,_("No upnp devices found"))
else:
firewall_reload(False)
raise YunoHostError(22,_("Can't connect to the igd device"))
# list the redirections :
for i in xrange(100):
p = upnp.getgenericportmapping(i)
if p is None: break
upnp.deleteportmapping(p[0], p[1])
def firewall_installupnp():
"""
Add upnp cron
Keyword arguments:
None
Return
None
"""
with open('firewall.yml', 'r') as f:
firewall = yaml.load(f)
firewall['UPNP']=True;
os.system("touch /etc/cron.d/yunohost-firewall")
os.system("echo '*/50 * * * * root yunohost firewall reload -u>>/dev/null'>/etc/cron.d/yunohost-firewall")
win_msg(_("UPNP cron installed"))
os.system("mv firewall.yml firewall.yml.old")
with open('firewall.yml', 'w') as f:
yaml.dump(firewall, f)
def firewall_removeupnp():
"""
Remove upnp cron
Keyword arguments:
None
Return
None
"""
with open('firewall.yml', 'r') as f:
firewall = yaml.load(f)
firewall['UPNP']=False;
try:
os.remove("/etc/cron.d/yunohost-firewall")
except:
raise YunoHostError(167,_("UPNP cron was not installed!"))
win_msg(_("UPNP cron removed"))
os.system("mv firewall.yml firewall.yml.old")
with open('firewall.yml', 'w') as f:
yaml.dump(firewall, f)
def firewall_checkupnp():
"""
Check if UPNP is installed
Keyword arguments:
None
Return
0 if installed
1 if not
"""
with open('firewall.yml', 'r') as f:
firewall = yaml.load(f)
if firewall['UPNP']:
win_msg(_("UPNP is activated"))
else:
raise YunoHostError(167,_("UPNP not activated!"))
def firewall_stop():
"""
Stop firewall
Keyword arguments:
None
Return
None
"""
os.system ("iptables -P INPUT ACCEPT")
os.system ("iptables -F")
os.system ("iptables -X")
os.system ("ip6tables -P INPUT ACCEPT")
os.system ("ip6tables -F")
os.system ("ip6tables -X")
if(os.path.exists("/etc/cron.d/yunohost-firewall")):
firewall_removeupnp()

View file

@ -81,16 +81,18 @@ def tools_maindomain(old_domain, new_domain):
""" """
if not old_domain: if not old_domain:
with open('/usr/share/yunohost/yunohost-config/others/current_host', 'r') as f: with open('/etc/yunohost/current_host', 'r') as f:
old_domain = f.readline().rstrip() old_domain = f.readline().rstrip()
validate(r'^([a-zA-Z0-9]{1}([a-zA-Z0-9\-]*[a-zA-Z0-9])*)(\.[a-zA-Z0-9]{1}([a-zA-Z0-9\-]*[a-zA-Z0-9])*)*(\.[a-zA-Z]{1}([a-zA-Z0-9\-]*[a-zA-Z0-9])*)$', old_domain) validate(r'^([a-zA-Z0-9]{1}([a-zA-Z0-9\-]*[a-zA-Z0-9])*)(\.[a-zA-Z0-9]{1}([a-zA-Z0-9\-]*[a-zA-Z0-9])*)*(\.[a-zA-Z]{1}([a-zA-Z0-9\-]*[a-zA-Z0-9])*)$', old_domain)
config_files = [ config_files = [
'/etc/prosody/conf.avail/localhost.cfg.lua',
'/etc/postfix/main.cf', '/etc/postfix/main.cf',
'/etc/dovecot/dovecot.conf', '/etc/dovecot/dovecot.conf',
'/etc/lemonldap-ng/lemonldap-ng.ini', '/etc/lemonldap-ng/lemonldap-ng.ini',
'/etc/hosts', '/etc/hosts',
'/usr/share/yunohost/yunohost-config/others/startup',
] ]
config_dir = [] config_dir = []
@ -122,12 +124,13 @@ def tools_maindomain(old_domain, new_domain):
lemon_conf.write(line + '\n') lemon_conf.write(line + '\n')
os.system('rm /etc/yunohost/apache/domains/' + old_domain + '.d/*.sso.conf') # remove SSO apache conf dir from old domain conf (fail if postinstall) os.system('rm /etc/yunohost/apache/domains/' + old_domain + '.d/*.fixed.conf') # remove SSO apache conf dir from old domain conf (fail if postinstall)
tmp = '/usr/share/yunohost/yunohost-config' tmp = '/usr/share/yunohost/yunohost-config'
command_list = [ command_list = [
'cp /etc/yunohost/apache/templates/fixed.sso.conf /etc/yunohost/apache/domains/' + new_domain + '.d/fixed.sso.conf', # add SSO apache conf dir to new domain conf 'cp /etc/yunohost/apache/templates/sso.fixed.conf /etc/yunohost/apache/domains/' + new_domain + '.d/sso.fixed.conf', # add SSO apache conf dir to new domain conf
'cp /etc/yunohost/apache/templates/admin.fixed.conf /etc/yunohost/apache/domains/' + new_domain + '.d/admin.fixed.conf',
'/usr/share/lemonldap-ng/bin/lmYnhMoulinette', '/usr/share/lemonldap-ng/bin/lmYnhMoulinette',
'/etc/init.d/hostname.sh', '/etc/init.d/hostname.sh',
'echo "01" > '+ tmp +'/ssl/yunoCA/serial', 'echo "01" > '+ tmp +'/ssl/yunoCA/serial',
@ -140,7 +143,7 @@ def tools_maindomain(old_domain, new_domain):
'cp '+ tmp +'/ssl/yunoCA/ca/cacert.pem /etc/ssl/certs/ca-yunohost_crt.pem', 'cp '+ tmp +'/ssl/yunoCA/ca/cacert.pem /etc/ssl/certs/ca-yunohost_crt.pem',
'cp '+ tmp +'/ssl/yunoCA/certs/yunohost_key.pem /etc/ssl/private/', 'cp '+ tmp +'/ssl/yunoCA/certs/yunohost_key.pem /etc/ssl/private/',
'cp '+ tmp +'/ssl/yunoCA/newcerts/01.pem /etc/ssl/certs/yunohost_crt.pem', 'cp '+ tmp +'/ssl/yunoCA/newcerts/01.pem /etc/ssl/certs/yunohost_crt.pem',
'echo '+ new_domain +' > /usr/share/yunohost/yunohost-config/others/current_host', 'echo '+ new_domain +' > /etc/yunohost/current_host',
'service apache2 restart', 'service apache2 restart',
'service postfix restart' 'service postfix restart'
] ]
@ -166,7 +169,7 @@ def tools_postinstall(domain, password):
""" """
with YunoHostLDAP(password='yunohost') as yldap: with YunoHostLDAP(password='yunohost') as yldap:
try: try:
with open('/usr/share/yunohost/yunohost-config/others/installed') as f: pass with open('/etc/yunohost/installed') as f: pass
except IOError: except IOError:
print('Installing YunoHost') print('Installing YunoHost')
else: else:
@ -181,6 +184,6 @@ def tools_postinstall(domain, password):
# Change LDAP admin password # Change LDAP admin password
tools_adminpw(old_password='yunohost', new_password=password) tools_adminpw(old_password='yunohost', new_password=password)
os.system('touch /usr/share/yunohost/yunohost-config/others/installed') os.system('touch /etc/yunohost/installed')
win_msg(_("YunoHost has been successfully configured")) win_msg(_("YunoHost has been successfully configured"))

View file

@ -25,7 +25,7 @@ def user_list(fields=None, filter=None, limit=None, offset=None):
with YunoHostLDAP() as yldap: with YunoHostLDAP() as yldap:
user_attrs = ['uid', 'mail', 'cn', 'mailalias'] user_attrs = ['uid', 'mail', 'cn', 'mailalias']
attrs = [] attrs = []
result_dict = {} result_list = []
if offset: offset = int(offset) if offset: offset = int(offset)
else: offset = 0 else: offset = 0
if limit: limit = int(limit) if limit: limit = int(limit)
@ -46,7 +46,7 @@ def user_list(fields=None, filter=None, limit=None, offset=None):
if result and len(result) > (0 + offset) and limit > 0: if result and len(result) > (0 + offset) and limit > 0:
i = 0 + offset i = 0 + offset
for user in result[i:]: for user in result[i:]:
if i <= limit: if i - offset < limit:
entry = { entry = {
'Username': user['uid'][0], 'Username': user['uid'][0],
'Fullname': user['cn'][0], 'Fullname': user['cn'][0],
@ -57,12 +57,12 @@ def user_list(fields=None, filter=None, limit=None, offset=None):
if 'mailalias' in user: if 'mailalias' in user:
entry['Mail Aliases'] = user['mailalias'] entry['Mail Aliases'] = user['mailalias']
result_dict[str(i)] = entry result_list.append(entry)
i += 1 i += 1
else: else:
raise YunoHostError(167, _("No user found")) raise YunoHostError(167, _("No user found"))
return result_dict return { 'Users' : result_list }
def user_create(username, firstname, lastname, mail, password): def user_create(username, firstname, lastname, mail, password):
@ -300,8 +300,8 @@ def user_info(user_or_mail):
raise YunoHostError(22, _("Unknown user/mail")) raise YunoHostError(22, _("Unknown user/mail"))
result_dict = { result_dict = {
'Username': user['uid'], 'Username': user['uid'][0],
'Fullname': user['cn'], 'Fullname': user['cn'][0],
'Mail': user['mail'][0] 'Mail': user['mail'][0]
} }