Commit 6533148d authored by zhifan huang's avatar zhifan huang

checkoutunittest's re6st_wrap for use tempdir to place unix socket file

parent acf43194
import os """wrap the deploy of re6st node, ease the creation of cert
import sys file and run of the node
"""
import json import json
import shutil import shutil
import sqlite3 import sqlite3
...@@ -7,17 +8,19 @@ import weakref ...@@ -7,17 +8,19 @@ import weakref
import ipaddress import ipaddress
import time import time
import re import re
import tempfile
import logging
from subprocess import PIPE, call from subprocess import PIPE, call
from pathlib2 import Path from pathlib2 import Path
import logging
import re6st.tests.tools as tools import re6st.tests.tools as tools
WORK_DIR = Path(__file__).parent.resolve() / "temp_net_test" WORK_DIR = Path(__file__).parent / "temp_net_test"
DH_FILE = WORK_DIR / "dh2048.pem" DH_FILE = WORK_DIR / "dh2048.pem"
RE6STNET = "re6stnet" RE6STNET = "re6stnet"
RE6ST_REGISTRY = "re6st-registry" RE6ST_REGISTRY = "re6st-registry"
#RE6ST_REGISTRY = "python -m re6st.cli.registry"
RE6ST_CONF = "re6st-conf" RE6ST_CONF = "re6st-conf"
def initial(): def initial():
...@@ -25,8 +28,8 @@ def initial(): ...@@ -25,8 +28,8 @@ def initial():
if not WORK_DIR.exists(): if not WORK_DIR.exists():
WORK_DIR.mkdir() WORK_DIR.mkdir()
if not DH_FILE.exists(): if not DH_FILE.exists():
call("openssl dhparam -out %s 2048" % str(DH_FILE), shell=True) logging.info("create dh file")
call(['openssl', 'dhparam', '-out', str(DH_FILE), '2048'], stderr=PIPE)
def ip_to_serial(ip6): def ip_to_serial(ip6):
"""convert ipv6 address to serial""" """convert ipv6 address to serial"""
...@@ -34,7 +37,6 @@ def ip_to_serial(ip6): ...@@ -34,7 +37,6 @@ def ip_to_serial(ip6):
ip6 = "1{:x}".format(int(ip6)).rstrip('0') ip6 = "1{:x}".format(int(ip6)).rstrip('0')
return int(ip6, 16) return int(ip6, 16)
def wait_ps(p, timeout=1, sec=0.1): def wait_ps(p, timeout=1, sec=0.1):
"""implement timeout of wait""" """implement timeout of wait"""
now = time.time() now = time.time()
...@@ -46,7 +48,7 @@ def wait_ps(p, timeout=1, sec=0.1): ...@@ -46,7 +48,7 @@ def wait_ps(p, timeout=1, sec=0.1):
class Re6stRegistry(object): class Re6stRegistry(object):
"""class run a re6st-registry service on a namespace""" """class run a re6st-registry service on a namespace"""
registry_seq = -1 registry_seq = 0
def __init__(self, node, ip6, recreate=False): def __init__(self, node, ip6, recreate=False):
self.node = node self.node = node
...@@ -61,7 +63,7 @@ class Re6stRegistry(object): ...@@ -61,7 +63,7 @@ class Re6stRegistry(object):
self.ca_crt = self.path / "ca.cert" self.ca_crt = self.path / "ca.cert"
self.log = self.path / "registry.log" self.log = self.path / "registry.log"
self.db = self.path / "registry.db" self.db = self.path / "registry.db"
self.run_path = self.path / "run" self.run_path = tempfile.mkdtemp()
if recreate and self.path.exists(): if recreate and self.path.exists():
shutil.rmtree(str(self.path)) shutil.rmtree(str(self.path))
...@@ -71,10 +73,15 @@ class Re6stRegistry(object): ...@@ -71,10 +73,15 @@ class Re6stRegistry(object):
# use hash to identify the registry # use hash to identify the registry
with self.ca_key.open() as f: with self.ca_key.open() as f:
text = f.readlines() text = f.read()
text = ''.join(text)
self.ident = hash(text) self.ident = hash(text)
# clear log file
if self.log.exists():
self.log.unlink()
self.clean()
self.run() self.run()
# wait the servcice started # wait the servcice started
...@@ -89,43 +96,55 @@ class Re6stRegistry(object): ...@@ -89,43 +96,55 @@ class Re6stRegistry(object):
time.sleep(.1) time.sleep(.1)
"""]) """])
try: try:
wait_ps(p, 5) wait_ps(p, 10)
except Exception as e: except Exception as e:
logging.error("{}: {}", self.name, e) logging.error("registry failed to start, %s: %s", self.name, e)
raise e raise e
logging.info("re6st service started") logging.info("re6st service started")
@classmethod @classmethod
def generate_name(cls): def generate_name(cls):
cls.registry_seq += 1 cls.registry_seq += 1
return "registry_{}".format(cls.registry_seq) return "registry_{}".format(cls.registry_seq)
@property @property
def url(self): def url(self):
return "http://{ip}/".format(ip=self.ip) return "http://{ip}/".format(ip=self.ip)
def create_registry(self): def create_registry(self):
self.path.mkdir() self.path.mkdir()
tools.create_ca_file(str(self.ca_key), str(self.ca_crt), tools.create_ca_file(str(self.ca_key), str(self.ca_crt),
serial=ip_to_serial(self.ip6)) serial=ip_to_serial(self.ip6))
#python -m re6st.cli.registry
def run(self): def run(self):
cmd = ("{script} --ca {ca} --key {key} --dh {dh} --ipv4 10.42.0.0/16 8 " cmd = ("{script} --ca {ca} --key {key} --dh {dh} --ipv4 10.42.0.0/16 8 "
" --logfile {log} --db {db} --run {run} --hello 4 --mailhost s -v4") " --logfile {log} --db {db} --run {run} --hello 4 --mailhost s "
"-v4")
cmd = cmd.format(script=RE6ST_REGISTRY, ca=self.ca_crt, cmd = cmd.format(script=RE6ST_REGISTRY, ca=self.ca_crt,
key=self.ca_key, dh=DH_FILE, log=self.log, db=self.db, key=self.ca_key, dh=DH_FILE, log=self.log, db=self.db,
run=self.run_path).split() run=self.run_path).split()
logging.info("run registry %s at ns: %s with cmd: %s",
self.name, self.node.pid, " ".join(cmd))
self.proc = self.node.Popen(cmd, stdout=PIPE, stderr=PIPE) self.proc = self.node.Popen(cmd, stdout=PIPE, stderr=PIPE)
def clean(self):
"""remove the file created last time"""
for f in [self.log]:
if f.exists():
f.unlink()
def __del__(self):
try:
logging.debug("teminate process %s", self.proc.pid)
self.proc.terminate()
self.proc.wait(1)
except:
pass
class Re6stNode(object): class Re6stNode(object):
"""class run a re6stnet service on a namespace""" """class run a re6stnet service on a namespace"""
node_seq = -1 node_seq = 0
def __init__(self, node, registry, name=None, recreate=False): def __init__(self, node, registry, name=None, recreate=False):
""" """
...@@ -139,14 +158,18 @@ class Re6stNode(object): ...@@ -139,14 +158,18 @@ class Re6stNode(object):
self.path = WORK_DIR / self.name self.path = WORK_DIR / self.name
self.email = self.name + "@example.com" self.email = self.name + "@example.com"
self.run_path = self.path / "run" if self.name == self.registry.name:
self.run_path = self.registry.run_path
else:
self.run_path = tempfile.mkdtemp()
self.log = self.path / "re6stnet.log"
self.crt = self.path / "cert.crt" self.crt = self.path / "cert.crt"
self.key = self.path / 'cert.key' self.key = self.path / 'cert.key'
self.console = self.run_path / "console.sock" self.console = self.run_path + "/console.sock"
self.data_file = self.path / "data.json" # contain data for restart node self.data_file = self.path / "data.json" # contain data for restart node
# condition, node of the registry
# condition node of the registry
if self.name == self.registry.name: if self.name == self.registry.name:
self.ip6 = self.registry.ip6 self.ip6 = self.registry.ip6
if not self.crt.exists(): if not self.crt.exists():
...@@ -167,25 +190,30 @@ class Re6stNode(object): ...@@ -167,25 +190,30 @@ class Re6stNode(object):
if not self.path.exists(): if not self.path.exists():
self.path.mkdir() self.path.mkdir()
self.create_node() self.create_node()
sys.stderr.write("{}'s subnet is {}\n".format(self.name, self.ip6))
logging.debug("%s's subnet is %s", self.name, self.ip6)
self.clean()
def __repr__(self):
return self.name
@classmethod @classmethod
def generate_name(cls): def generate_name(cls):
cls.node_seq += 1 cls.node_seq += 1
return "node_{}".format(cls.node_seq) return "node_{}".format(cls.node_seq)
def create_node(self): def create_node(self):
"""create necessary file for node""" """create necessary file for node"""
sys.stderr.write("create file for node {}".format(self.name)) logging.info("create dir of node %s", self.name)
cmd = "{script} --registry {registry_url} --email {email}" cmd = "{script} --registry {registry_url} --email {email}"
cmd = cmd.format(script=RE6ST_CONF, registry_url=self.registry.url, cmd = cmd.format(script=RE6ST_CONF, registry_url=self.registry.url,
email=self.email).split() email=self.email).split()
p = self.node.Popen(cmd, stdin=PIPE, stdout=PIPE, p = self.node.Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE,
cwd=str(self.path)) cwd=str(self.path))
# read token
db = sqlite3.connect(str(self.registry.db), isolation_level=None) db = sqlite3.connect(str(self.registry.db), isolation_level=None)
count = 0 count = 0
token = None token = None
while not token: while not token:
...@@ -194,14 +222,17 @@ class Re6stNode(object): ...@@ -194,14 +222,17 @@ class Re6stNode(object):
(self.email,)).fetchone() (self.email,)).fetchone()
count += 1 count += 1
if count > 100: if count > 100:
p.terminate()
raise Exception("can't connect to the Register") raise Exception("can't connect to the Register")
out, _ = p.communicate(str(token[0])) out, _ = p.communicate(str(token[0]))
# logging.debug("re6st-conf output: {}".format(out))
# find the ipv6 subnet of node
self.ip6 = re.search('(?<=subnet: )[0-9:a-z]+', out).group(0) self.ip6 = re.search('(?<=subnet: )[0-9:a-z]+', out).group(0)
data = {'ip6': self.ip6, 'hash': self.registry.ident} data = {'ip6': self.ip6, 'hash': self.registry.ident}
with open(str(self.data_file), 'w') as f: with open(str(self.data_file), 'w') as f:
json.dump(data, f) json.dump(data, f)
logging.info("create dir of node %s finish", self.name)
def run(self, *args): def run(self, *args):
"""execute re6stnet""" """execute re6stnet"""
...@@ -214,4 +245,33 @@ class Re6stNode(object): ...@@ -214,4 +245,33 @@ class Re6stNode(object):
cert=self.crt, key=self.key, registry=self.registry.url, cert=self.crt, key=self.key, registry=self.registry.url,
console=self.console).split() console=self.console).split()
cmd += args cmd += args
logging.info("run node %s at ns: %s with cmd: %s",
self.name, self.node.pid, " ".join(cmd))
self.proc = self.node.Popen(cmd, stdout=PIPE, stderr=PIPE) self.proc = self.node.Popen(cmd, stdout=PIPE, stderr=PIPE)
def clean(self):
"""remove the file created last time"""
for name in ["re6stnet.log", "babeld.state", "cache.db", "babeld.log"]:
f = self.path / name
if f.exists():
f.unlink()
def stop(self):
"""stop running re6stnet process"""
logging.debug("%s teminate process %s", self.name, self.proc.pid)
self.proc.terminate()
# timeout only in python3. deadlock maybe
wait_ps(self.proc, 2)
def __del__(self):
"""teminate process and rm temp dir"""
try:
self.stop()
except Exception as e:
logging.warn("%s: %s", self.name, e)
# python2 seems auto clean the tempdir
# try:
# shutil.rmtree(self.run_path)
# except Exception as e:
# logging.error("{}: {}".format(self.name, e))
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