Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/sugar_network
diff options
context:
space:
mode:
authorAleksey Lim <alsroot@sugarlabs.org>2014-05-08 11:41:25 (GMT)
committer Aleksey Lim <alsroot@sugarlabs.org>2014-05-08 11:41:25 (GMT)
commit70c1b1a26a610c082a49bd5fb29e6dca2bf47943 (patch)
tree935412a227a5bcd63580010a65a15e5dcc5d3050 /sugar_network
parent5ebeca1a965aa4028fde7a73c7baffbdba705ef5 (diff)
Start local node router for admin needs
Diffstat (limited to 'sugar_network')
-rw-r--r--sugar_network/node/auth.py23
-rw-r--r--sugar_network/node/routes.py9
-rw-r--r--sugar_network/node/slave.py4
-rw-r--r--sugar_network/toolkit/__init__.py8
-rw-r--r--sugar_network/toolkit/application.py18
-rw-r--r--sugar_network/toolkit/coroutine.py26
-rw-r--r--sugar_network/toolkit/http.py3
-rw-r--r--sugar_network/toolkit/router.py3
8 files changed, 62 insertions, 32 deletions
diff --git a/sugar_network/node/auth.py b/sugar_network/node/auth.py
index d14bde6..13a9608 100644
--- a/sugar_network/node/auth.py
+++ b/sugar_network/node/auth.py
@@ -62,14 +62,25 @@ class Principal(str):
@property
def cap_create_with_guid(self):
- return self._caps & 1
+ return self._caps & 2
@cap_create_with_guid.setter
def cap_create_with_guid(self, value):
if value:
- self._caps |= 1
+ self._caps |= 2
else:
- self._caps ^= 1
+ self._caps ^= 2
+
+ @property
+ def cap_admin(self):
+ return self._caps & 4
+
+ @cap_admin.setter
+ def cap_admin(self, value):
+ if value:
+ self._caps |= 4
+ else:
+ self._caps ^= 4
def __enter__(self):
self._backup = self._caps
@@ -141,3 +152,9 @@ class SugarAuth(object):
# TODO
return principal
+
+
+class RootAuth(object):
+
+ def logon(self, request):
+ return Principal('root', 0xFFFF)
diff --git a/sugar_network/node/routes.py b/sugar_network/node/routes.py
index 68beb65..79c4056 100644
--- a/sugar_network/node/routes.py
+++ b/sugar_network/node/routes.py
@@ -82,6 +82,9 @@ class NodeRoutes(db.Routes, FrontRoutes):
allowed = True
enforce(allowed, http.Forbidden, 'Authors only')
+ if op.acl & ACL.ADMIN:
+ enforce(this.principal.cap_admin, http.Forbidden, 'Admins only')
+
@postroute
def postroute(self, result, exception):
request = this.request
@@ -172,9 +175,9 @@ class NodeRoutes(db.Routes, FrontRoutes):
return solution
@route('GET', ['context', None], cmd='resolve',
- arguments={'requires': list, 'stability': list})
- def resolve(self):
- solution = self.solve()
+ arguments={'requires': list, 'stability': list, 'assume': list})
+ def resolve(self, assume=None):
+ solution = self.solve(assume)
return self.volume.blobs.get(solution[this.request.guid]['blob'])
@route('GET', [None, None], cmd='diff')
diff --git a/sugar_network/node/slave.py b/sugar_network/node/slave.py
index a1195ab..7bf29e2 100644
--- a/sugar_network/node/slave.py
+++ b/sugar_network/node/slave.py
@@ -57,7 +57,7 @@ class SlaveRoutes(NodeRoutes):
self._master_guid = urlsplit(master_api).netloc
self._master_api = master_api
- @route('POST', cmd='online_sync', acl=ACL.LOCAL,
+ @route('POST', cmd='online_sync', acl=ACL.AUTH | ACL.ADMIN,
arguments={'no_pull': bool})
def online_sync(self, no_pull=False):
conn = http.Connection(self._master_api)
@@ -70,7 +70,7 @@ class SlaveRoutes(NodeRoutes):
headers={'Transfer-Encoding': 'chunked'})
self._import(packets.decode(response.raw))
- @route('POST', cmd='offline_sync', acl=ACL.LOCAL)
+ @route('POST', cmd='offline_sync', acl=ACL.AUTH | ACL.ADMIN)
def offline_sync(self, path):
enforce(isabs(path), "Argument 'path' is not an absolute path")
diff --git a/sugar_network/toolkit/__init__.py b/sugar_network/toolkit/__init__.py
index bf80271..9cad5e0 100644
--- a/sugar_network/toolkit/__init__.py
+++ b/sugar_network/toolkit/__init__.py
@@ -34,7 +34,7 @@ BUFFER_SIZE = 1024 * 10
cachedir = Option(
'path to a directory to keep cached files; such files '
'might take considerable number of bytes',
- default='/var/cache/sugar-network', name='cachedir')
+ name='cachedir')
_logger = logging.getLogger('toolkit')
@@ -390,7 +390,7 @@ def unique_filename(root, filename):
class mkdtemp(str):
def __new__(cls, *args, **kwargs):
- if 'dir' not in kwargs:
+ if cachedir.value and 'dir' not in kwargs:
kwargs['dir'] = cachedir.value
if not exists(kwargs['dir']):
os.makedirs(kwargs['dir'])
@@ -431,7 +431,7 @@ def svg_to_png(data, w, h=None):
def TemporaryFile(*args, **kwargs):
- if 'dir' not in kwargs:
+ if cachedir.value and 'dir' not in kwargs:
kwargs['dir'] = cachedir.value
if not exists(kwargs['dir']):
os.makedirs(kwargs['dir'])
@@ -441,7 +441,7 @@ def TemporaryFile(*args, **kwargs):
class NamedTemporaryFile(object):
def __init__(self, *args, **kwargs):
- if 'dir' not in kwargs:
+ if cachedir.value and 'dir' not in kwargs:
kwargs['dir'] = cachedir.value
if not exists(kwargs['dir']):
os.makedirs(kwargs['dir'])
diff --git a/sugar_network/toolkit/application.py b/sugar_network/toolkit/application.py
index bc6b99c..670a2d3 100644
--- a/sugar_network/toolkit/application.py
+++ b/sugar_network/toolkit/application.py
@@ -175,8 +175,6 @@ class Application(object):
pass
def start(self):
- self._rundir = abspath(rundir.value or '/var/run/' + self.name)
-
cmd_name = self.args.pop(0)
try:
cmd = self._commands.get(cmd_name)
@@ -186,10 +184,11 @@ class Application(object):
logging.info('Load configuration from %s file(s)',
', '.join(Option.config_files))
- if cmd.options.get('keep_stdout') and not foreground.value:
- self._keep_stdout()
-
self.prolog()
+ self._rundir = abspath(rundir.value or '/var/run/' + self.name)
+
+ if cmd.options.get('keep_stdout') and not foreground.value:
+ self.reopen_logs()
exit(cmd() or 0)
except Exception:
printf.exception('%s %s', _('Aborted'), self.name)
@@ -214,9 +213,6 @@ class Application(object):
pid = None
return pid
- def ensure_run(self):
- pass
-
def ensure_pidfile(self):
if not exists(self._rundir):
os.makedirs(self._rundir)
@@ -237,7 +233,7 @@ class Application(object):
else:
print Option.help()
- def _keep_stdout(self):
+ def reopen_logs(self):
log_dir = abspath(logdir.value)
if not exists(log_dir):
os.makedirs(log_dir)
@@ -280,7 +276,6 @@ class Daemon(Application):
pass
time.sleep(.5)
- self.ensure_run()
if foreground.value:
self._launch()
else:
@@ -333,7 +328,7 @@ class Daemon(Application):
def sighup_cb():
logging.info('Reload %s on SIGHUP signal', self.name)
- self._keep_stdout()
+ self.reopen_logs()
coroutine.signal(signal.SIGINT, sigterm_cb, signal.SIGINT)
coroutine.signal(signal.SIGTERM, sigterm_cb, signal.SIGTERM)
@@ -343,7 +338,6 @@ class Daemon(Application):
try:
self.run()
finally:
- self.epilog()
os.unlink(pid_path)
def _daemonize(self):
diff --git a/sugar_network/toolkit/coroutine.py b/sugar_network/toolkit/coroutine.py
index 1f3d842..c3d4a47 100644
--- a/sugar_network/toolkit/coroutine.py
+++ b/sugar_network/toolkit/coroutine.py
@@ -80,13 +80,15 @@ def socket(*args, **kwargs):
return gevent.socket.socket(*args, **kwargs)
-def listen_unix_socket(path, backlog=5):
+def listen_unix_socket(path, backlog=5, reuse_address=False, mode=None):
# pylint: disable-msg=E1101
from tempfile import NamedTemporaryFile
import _socket
if exists(path):
- raise RuntimeError('The socket address is in use')
+ if not reuse_address:
+ raise RuntimeError('The socket address is in use')
+ os.unlink(path)
sock = socket(_socket.AF_UNIX, _socket.SOCK_STREAM)
sock.setblocking(0)
@@ -94,6 +96,8 @@ def listen_unix_socket(path, backlog=5):
with NamedTemporaryFile(dir=dirname(path)) as tmp_path:
pass
sock.bind(tmp_path.name)
+ if mode is not None:
+ os.chmod(tmp_path.name, mode)
try:
os.rename(tmp_path.name, path)
except Exception, error:
@@ -141,7 +145,11 @@ def Server(*args, **kwargs):
def WSGIServer(*args, **kwargs):
import gevent.wsgi
- class WSGIHandler(gevent.wsgi.WSGIHandler):
+ class Server(gevent.wsgi.WSGIServer):
+
+ http_log = kwargs.pop('http_log') if 'http_log' in kwargs else None
+
+ class Handler(gevent.wsgi.WSGIHandler):
def log_error(self, msg, *args):
if args:
@@ -149,14 +157,16 @@ def WSGIServer(*args, **kwargs):
_wsgi_logger.error('%s %s', self.format_request(), msg)
def log_request(self):
- _wsgi_logger.debug('%s', self.format_request())
+ logfile = server.http_log
+ if logfile is not None:
+ logfile.write(self.format_request())
+ logfile.write('\n')
kwargs['spawn'] = Pool()
if 'handler_class' not in kwargs:
- if logging.getLogger().level >= logging.DEBUG:
- WSGIHandler.log_request = lambda * args: None
- kwargs['handler_class'] = WSGIHandler
- return gevent.wsgi.WSGIServer(*args, **kwargs)
+ kwargs['handler_class'] = Handler
+ server = Server(*args, **kwargs)
+ return server
def Event():
diff --git a/sugar_network/toolkit/http.py b/sugar_network/toolkit/http.py
index f3c2ef8..51b34ee 100644
--- a/sugar_network/toolkit/http.py
+++ b/sugar_network/toolkit/http.py
@@ -119,6 +119,9 @@ class Connection(object):
self._session = None
self._auth_request = auth_request
+ if self.url and self.url.startswith('file://'):
+ self._session_args['trust_env'] = False
+
def __repr__(self):
return '<Connection url=%s>' % self.url
diff --git a/sugar_network/toolkit/router.py b/sugar_network/toolkit/router.py
index ba498d6..7b2186d 100644
--- a/sugar_network/toolkit/router.py
+++ b/sugar_network/toolkit/router.py
@@ -88,6 +88,7 @@ class ACL(object):
AGG_AUTHOR = 1 << 12
LOCAL = 1 << 20
+ ADMIN = 1 << 21
NAMES = {
CREATE: 'Create',
@@ -854,6 +855,8 @@ class _Route(object):
'ACL.AUTHOR requires longer path')
enforce(acl ^ ACL.AGG_AUTHOR or len(path) >= 3,
'ACL.AGG_AUTHOR requires longer path')
+ enforce(acl ^ ACL.ADMIN or acl & ACL.AUTH,
+ 'ACL.ADMIN without ACL.AUTH')
self.op = (method, cmd)
self.callback = callback