mirror of
https://github.com/tuna/tunasync.git
synced 2025-04-21 04:42:46 +00:00
control server
This commit is contained in:
parent
5725113a91
commit
199ca93e66
@ -10,6 +10,7 @@ concurrent = 2
|
|||||||
# interval in minutes
|
# interval in minutes
|
||||||
interval = 1
|
interval = 1
|
||||||
max_retry = 2
|
max_retry = 2
|
||||||
|
ctrl_addr = "/tmp/tunasync.sock"
|
||||||
|
|
||||||
[btrfs]
|
[btrfs]
|
||||||
service_dir = "{mirror_root}/_current/{mirror_name}"
|
service_dir = "{mirror_root}/_current/{mirror_name}"
|
||||||
|
49
tunasync/clt_server.py
Normal file
49
tunasync/clt_server.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#!/usr/bin/env python2
|
||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
import socket
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
class ControlServer(object):
|
||||||
|
|
||||||
|
def __init__(self, address, mgr_chan, cld_chan):
|
||||||
|
self.address = address
|
||||||
|
self.mgr_chan = mgr_chan
|
||||||
|
self.cld_chan = cld_chan
|
||||||
|
try:
|
||||||
|
os.unlink(self.address)
|
||||||
|
except OSError:
|
||||||
|
if os.path.exists(self.address):
|
||||||
|
raise Exception("file exists: {}".format(self.address))
|
||||||
|
|
||||||
|
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
|
self.sock.bind(self.address)
|
||||||
|
|
||||||
|
print("Control Server listening on: {}".format(self.address))
|
||||||
|
self.sock.listen(1)
|
||||||
|
|
||||||
|
def serve_forever(self):
|
||||||
|
while 1:
|
||||||
|
conn, _ = self.sock.accept()
|
||||||
|
|
||||||
|
try:
|
||||||
|
length = ord(conn.recv(1))
|
||||||
|
content = conn.recv(length)
|
||||||
|
cmd = json.loads(content)
|
||||||
|
self.mgr_chan.put(("CMD", (cmd['cmd'], cmd['target'])))
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
res = "Invalid Command"
|
||||||
|
else:
|
||||||
|
res = self.cld_chan.get()
|
||||||
|
|
||||||
|
conn.sendall(chr(len(res)) + res)
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
def run_control_server(address, mgr_chan, cld_chan):
|
||||||
|
cs = ControlServer(address, mgr_chan, cld_chan)
|
||||||
|
cs.serve_forever()
|
||||||
|
|
||||||
|
# vim: ts=4 sw=4 sts=4 expandtab
|
@ -29,7 +29,7 @@ def run_job(sema, child_q, manager_q, provider, **settings):
|
|||||||
aquired = True
|
aquired = True
|
||||||
|
|
||||||
status = "syncing"
|
status = "syncing"
|
||||||
manager_q.put((provider.name, status))
|
manager_q.put(("UPDATE", (provider.name, status)))
|
||||||
try:
|
try:
|
||||||
for hook in provider.hooks:
|
for hook in provider.hooks:
|
||||||
hook.before_job(name=provider.name)
|
hook.before_job(name=provider.name)
|
||||||
@ -66,12 +66,12 @@ def run_job(sema, child_q, manager_q, provider, **settings):
|
|||||||
provider.name, provider.interval
|
provider.name, provider.interval
|
||||||
))
|
))
|
||||||
|
|
||||||
manager_q.put((provider.name, status))
|
manager_q.put(("UPDATE", (provider.name, status)))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
msg = child_q.get(timeout=provider.interval * 60)
|
msg = child_q.get(timeout=provider.interval * 60)
|
||||||
if msg == "terminate":
|
if msg == "terminate":
|
||||||
manager_q.put((provider.name, "QUIT"))
|
manager_q.put(("CONFIG_ACK", (provider.name, "QUIT")))
|
||||||
break
|
break
|
||||||
except Queue.Empty:
|
except Queue.Empty:
|
||||||
pass
|
pass
|
||||||
|
@ -9,6 +9,7 @@ from . import jobs
|
|||||||
from .hook import JobHook
|
from .hook import JobHook
|
||||||
from .mirror_config import MirrorConfig
|
from .mirror_config import MirrorConfig
|
||||||
from .status_manager import StatusManager
|
from .status_manager import StatusManager
|
||||||
|
from .clt_server import run_control_server
|
||||||
|
|
||||||
|
|
||||||
class TUNASync(object):
|
class TUNASync(object):
|
||||||
@ -46,6 +47,15 @@ class TUNASync(object):
|
|||||||
self.status_file = self._settings["global"]["status_file"]
|
self.status_file = self._settings["global"]["status_file"]
|
||||||
self.status_manager = StatusManager(self, self.status_file)
|
self.status_manager = StatusManager(self, self.status_file)
|
||||||
|
|
||||||
|
self.ctrl_addr = self._settings["global"]["ctrl_addr"]
|
||||||
|
self.ctrl_channel = Queue()
|
||||||
|
p = Process(
|
||||||
|
target=run_control_server,
|
||||||
|
args=(self.ctrl_addr, self.channel, self.ctrl_channel),
|
||||||
|
)
|
||||||
|
p.start()
|
||||||
|
self.processes["CTRL_SERVER"] = (self.ctrl_channel, p)
|
||||||
|
|
||||||
def add_hook(self, h):
|
def add_hook(self, h):
|
||||||
assert isinstance(h, JobHook)
|
assert isinstance(h, JobHook)
|
||||||
self._hooks.append(h)
|
self._hooks.append(h)
|
||||||
@ -94,20 +104,7 @@ class TUNASync(object):
|
|||||||
signal.signal(signal.SIGUSR1, self.reload_mirrors)
|
signal.signal(signal.SIGUSR1, self.reload_mirrors)
|
||||||
signal.signal(signal.SIGUSR2, self.reload_mirrors_force)
|
signal.signal(signal.SIGUSR2, self.reload_mirrors_force)
|
||||||
|
|
||||||
while 1:
|
self.run_forever()
|
||||||
try:
|
|
||||||
name, status = self.channel.get()
|
|
||||||
except IOError:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if status == "QUIT":
|
|
||||||
print("New configuration applied to {}".format(name))
|
|
||||||
self.run_provider(name)
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
self.status_manager.update_status(name, status)
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
|
|
||||||
def run_provider(self, name):
|
def run_provider(self, name):
|
||||||
if name not in self.providers:
|
if name not in self.providers:
|
||||||
@ -170,5 +167,59 @@ class TUNASync(object):
|
|||||||
print("New mirror: {}".format(name))
|
print("New mirror: {}".format(name))
|
||||||
self.run_provider(name)
|
self.run_provider(name)
|
||||||
|
|
||||||
|
def run_forever(self):
|
||||||
|
while 1:
|
||||||
|
|
||||||
|
try:
|
||||||
|
msg_hdr, msg_body = self.channel.get()
|
||||||
|
except IOError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if msg_hdr == "UPDATE":
|
||||||
|
name, status = msg_body
|
||||||
|
try:
|
||||||
|
self.status_manager.update_status(name, status)
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
elif msg_hdr == "CONFIG_ACK":
|
||||||
|
name, status = msg_body
|
||||||
|
if status == "QUIT":
|
||||||
|
print("New configuration applied to {}".format(name))
|
||||||
|
self.run_provider(name)
|
||||||
|
|
||||||
|
elif msg_hdr == "CMD":
|
||||||
|
cmd, name = msg_body
|
||||||
|
if name not in self.mirrors:
|
||||||
|
self.ctrl_channel.put("Invalid target")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if cmd == "restart":
|
||||||
|
_, p = self.processes[name]
|
||||||
|
p.terminate()
|
||||||
|
self.run_provider(name)
|
||||||
|
res = "Restarted Job: {}".format(name)
|
||||||
|
|
||||||
|
elif cmd == "stop":
|
||||||
|
if name not in self.processes:
|
||||||
|
res = "{} not running".format(name)
|
||||||
|
self.ctrl_channel.put(res)
|
||||||
|
continue
|
||||||
|
|
||||||
|
_, p = self.processes.pop(name)
|
||||||
|
p.terminate()
|
||||||
|
res = "Stopped Job: {}".format(name)
|
||||||
|
|
||||||
|
elif cmd == "start":
|
||||||
|
if name in self.processes:
|
||||||
|
res = "{} already running".format(name)
|
||||||
|
self.ctrl_channel.put(res)
|
||||||
|
continue
|
||||||
|
|
||||||
|
self.run_provider(name)
|
||||||
|
res = "Started Job: {}".format(name)
|
||||||
|
else:
|
||||||
|
res = "Invalid command"
|
||||||
|
|
||||||
|
self.ctrl_channel.put(res)
|
||||||
# vim: ts=4 sw=4 sts=4 expandtab
|
# vim: ts=4 sw=4 sts=4 expandtab
|
||||||
|
40
tunasynctl.py
Executable file
40
tunasynctl.py
Executable file
@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/env python2
|
||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
import sys
|
||||||
|
import socket
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(prog="tunasynctl")
|
||||||
|
parser.add_argument("-s", "--socket",
|
||||||
|
default="/var/run/tunasync.sock", help="socket file")
|
||||||
|
parser.add_argument("command", help="command")
|
||||||
|
parser.add_argument("target", help="target")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
|
|
||||||
|
try:
|
||||||
|
sock.connect(args.socket)
|
||||||
|
except socket.error as msg:
|
||||||
|
print(msg)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
pack = json.dumps({
|
||||||
|
'cmd': args.command,
|
||||||
|
'target': args.target,
|
||||||
|
})
|
||||||
|
|
||||||
|
try:
|
||||||
|
sock.sendall(chr(len(pack)) + pack)
|
||||||
|
length = ord(sock.recv(1))
|
||||||
|
print(sock.recv(length))
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
finally:
|
||||||
|
sock.close()
|
||||||
|
|
||||||
|
# vim: ts=4 sw=4 sts=4 expandtab
|
Loading…
x
Reference in New Issue
Block a user