Commit 3a26f3cd authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 938374de
......@@ -246,6 +246,8 @@ setup(
'six', # compat py2/py3
'psutil', # demo_zbigarray
'pygolang', # wcfs
],
extras_require = {
......@@ -260,6 +262,9 @@ setup(
},
entry_points= {'console_scripts': [
# start wcfs
'wcfs = wendelin.wcfs:main',
# demo to test
'demo-zbigarray = wendelin.demo.demo_zbigarray:main',
]
......
# -*- coding: utf-8 -*-
# Copyright (C) 2018 Nexedi SA and Contributors.
# Kirill Smelkov <kirr@nexedi.com>
#
# This program is free software: you can Use, Study, Modify and Redistribute
# it under the terms of the GNU General Public License version 3, or (at your
# option) any later version, as published by the Free Software Foundation.
#
# You can also Link and Combine this program with other software covered by
# the terms of any of the Free Software licenses or any of the Open Source
# Initiative approved licenses and Convey the resulting work. Corresponding
# source of such a combination shall include the source code for all other
# software used.
#
# This program is distributed WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# See COPYING file for full licensing terms.
# See https://www.nexedi.com/licensing for rationale and options.
"""Module wcfs.py provides python gateway for spawning and interoperating with wcfs server
XXX doc
"""
import os, sys, hashlib, tempfile, subprocess, errno, time
import logging as log
from os.path import dirname
from pygolang import go, chan, select, default
# WCFS represents connection to wcfs server.
class WCFS(object):
# XXX + .zurl?
# .mountpoint path to mountpoint
# ._fwcfs /.wcfs opened
def __init__(self, mountpoint):
self.mountpoint = mountpoint
# XXX open a file to keep the server from going away (at least cleanly)
# run starts and runs wcfs server for ZODB @ zurl.
#
# it mounts wcfs at a location that is with 1-1 corresponence with zurl.
# it then waits for wcfs to exit (either due to unmount or an error).
#
# it is an error if wcfs was already started.
#
# run(zurl).
def run(zurl):
mntpt = _mntpt_4zurl(zurl)
# try opening .wcfs - it is an error if we can do it.
# XXX -> option to wcfs itself
try:
f = open(mntpt + "/.wcfs")
except IOError as e:
if e.errno != errno.ENOENT:
raise
else:
f.close()
raise RuntimeError("wcfs: start %s: already started" % zurl)
# seems to be ok to start
# XXX race window if something starts after ^^^ check
subprocess.call([_wcfs_exe(), zurl, mntpt], close_fds=True)
# join connects to wcfs server for ZODB @ zurl.
#
# if wcfs for that service was already started, join connects to it.
# otherwise it starts wcfs for zurl if autostart is True or (None and system
# default for autostart is True). XXX
#
# join(zurl) -> WCFS.
def join(zurl, autostart=None):
mntpt = _mntpt_4zurl(zurl)
# try opening .wcfs - if we succeed - it is already mounted.
# XXX -> wcfs itself?
try:
f = open(mntpt + "/.wcfs")
except IOError as e:
if e.errno != errno.ENOENT:
raise
else:
# already have it
return WCFS(mntpt, f)
# XXX autostart=None processing
if not autostart:
raise RuntimeError("wcfs: join %s: server not started" % zurl)
log.info("wcfs: starting for %s ...", zurl)
# cancelch cancels wcfs server running (and waitmounted in initialization phase)
cancelch = chan()
# wcfs spawns and monitors wcfs server. it is running until either wcfs
# server terminates or cancel.
ewcfs = chan(1) # err | None
def wcfs():
err = None
try:
p = subprocess.Popen([_wcfs_exe(), zurl, mntpt], close_fds=True)
while 1:
ret = p.poll()
if ret is not None:
err = "wcfs: exited with %s" % ret
break
_, _rx = select(
cancelch.recv, # 0
default, # 1
)
if _ == 0:
p.terminate()
break
time.sleep(1)
except Exception as e:
log.exception("wcfs server")
err = "wcfs: %s" % e # XXX wrap with errctx
ewcfs.send(err)
# waitmounted waits till wcfs mount is ready.
mounted = chan(1) # file | err
def waitmounted():
err = None
# XXX try/except + errctx
while 1:
if os.path.exists("%s/.wcfs" % mntpt):
break
_, _rx = select(
cancelch.recv, # 0
default, # 1
)
if _ == 0:
err = "waitmounted: cancel"
break
time.sleep(1)
mounted.send(err)
# spawn wcfs and wait till it is mounted.
go(wcfs)
go(waitmounted)
_, _rx = select(
ewcfs.recv, # 0
mounted.recv, # 1
)
if _ == 0:
# wcfs error
cancelch.close()
raise RuntimeError(_rx)
if _ == 1:
if not isinstance(_rx, file):
cancelch.close()
# mounted ok - construct WCFS object
# XXX do we need to remember cancelch in WCFS and close it upon leaving?
f = _rx
return WCFS(mntpt, f)
# _wcfs_exe returns path to wcfs executable.
# TODO install wcfs exe along wcfs/ py package.
def _wcfs_exe():
return '%s/wcfs' % dirname(__file__)
# _mntpt_4zurl returns wcfs should-be mountpoint for ZODB @ zurl.
def _mntpt_4zurl(zurl):
# XXX stub.
# XXX what is zurl is zconfig://... ? -> then we have to look inside?
m = hashlib.sha1()
m.update(zurl)
return "%s/wcfs/%s" % (tempfile.gettempdir(), m.hexdigest())
# if called as main just -> run(argv[1])
def main():
run(sys.argv[1])
......@@ -241,6 +241,9 @@ package main
// link above), but better we have proper FUSE flag for filesystem server to
// tell the kernel it is fully responsible for invalidating pagecache.
// usage: wcfs zurl mountpoint
// /.wcfs + option to prevent starting if wcfs was already started ?
// /zurl ?
func main() {
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment