publik-dump: add tests

This commit is contained in:
Nicolas Roche 2021-10-23 06:15:47 +02:00
parent de91f1cee8
commit 1e221eb962
11 changed files with 580 additions and 180 deletions

View File

@ -1 +1,4 @@
output
__pycache__
*.pyc
*~

View File

@ -1,179 +0,0 @@
#!/usr/bin/python3
import argparse
import json
import os
import pickle
import subprocess
parser = argparse.ArgumentParser()
parser.add_argument("action", default="dump", choices=["tenantinfo", "tenanturls", "dump", "restore", "invalidate"])
parser.add_argument("host", help="origin host")
parser.add_argument("tenant", help="hobo tenant url")
parser.add_argument("--update", action="store_true")
parser.add_argument("--target", help="destination host")
parser.add_argument("--dbtarget", help="destination host")
args = parser.parse_args()
host_folder = "output/%s" % args.host
def run(cmd):
print("+ %s" % cmd)
return subprocess.run(cmd, shell=True, check=True, stdout=subprocess.PIPE)
def get_dump_folder(service):
dump_folder = "%s/%s" % (host_folder, service["url"])
if not os.path.isdir(dump_folder):
os.mkdir(dump_folder)
return dump_folder
def dump_tenant_files(tenant):
for service in tenant["services"]:
dump_folder = get_dump_folder(service)
output = "%s/%s.tar.xz" % (dump_folder, service["url"])
run(
"ssh %s.%s 'sudo tar -C %s -Jcf - %s' > %s"
% (service["name"], args.host, service["path"], service["url"], output)
)
def restore_tenant_files(tenant):
assert run("ssh %s hostname -f" % args.target).stdout.decode().strip() == args.target
import pdb; pdb.set_trace()
# for service in tenant["services"]:
# dump_folder = get_dump_folder(service)
# input_file = "%s/%s.tar.xz" % (dump_folder, service["url"])
# run(
# "cat %s | ssh %s.%s 'sudo tar -C %s -Jxf -'"
# % (input_file, service["name"], args.target, service["path"])
# )
def dump_tenant_databases(tenant):
# node2.test.saas.entrouvert.org -> db2.test.saas.entrouvert.org
domain = '.'.join(args.host.split('.')[1:])
for service in tenant["services"]:
dump_folder = get_dump_folder(service)
if service["name"] == "wcs":
dump_file = "%s/%s.sql.gz" % (dump_folder, service["database"])
run(
"ssh db2.%s 'sudo -u postgres pg_dump -Fc %s' > %s"
% (domain, service["database"], dump_file)
)
else:
dump_file = "%s/%s.sql.gz" % (dump_folder, service["schema"])
run(
"ssh db2.%s 'sudo -u postgres pg_dump -n %s -Fc %s' > %s"
% (domain, service["schema"], service["database"], dump_file)
)
def restore_tenant_databases(tenant):
assert run("ssh %s hostname -f" % args.dbtarget).stdout.decode().strip() == args.dbtarget
for service in tenant["services"]:
dump_folder = get_dump_folder(service)
import pdb; pdb.set_trace()
# if service["name"] == "wcs":
# dump_file = "%s/%s.sql.gz" % (dump_folder, service["database"])
# run(
# "ssh %s sudo -u postgres dropdb --if-exists %s"
# % (args.dbtarget, service["database"])
# )
# run(
# """ssh %s 'sudo -u postgres createdb %s --owner wcs --template="template0" --lc-collate=fr_FR.utf8 --lc-ctype=fr_FR.utf8'"""
# % (args.dbtarget, service["database"])
# )
# run(
# "cat %s | ssh %s sudo -u postgres pg_restore -d %s"
# % (dump_file, args.dbtarget, service["database"])
# )
# else:
# dump_file = "%s/%s.sql.gz" % (dump_folder, service["schema"])
# run(
# """ssh %s 'sudo -u postgres psql -c "drop schema if exists %s cascade" %s'"""
# % (args.dbtarget, service["schema"], service["database"])
# )
# run(
# "cat %s | ssh %s sudo -u postgres pg_restore -d %s"
# % (dump_file, args.dbtarget, service["database"])
# )
def parse_service(service):
if service["name"] == "authentic":
path = "/var/lib/authentic2-multitenant/tenants"
database = "authentic2_multitenant"
elif service["name"] == "wcs":
path = "/var/lib/wcs"
try:
wcs_config = run(
"ssh wcs.%s 'cat /var/lib/wcs/%s/config.pck 2>/dev/null || cat /var/lib/wcs/tenants/%s/config.pck'"
% (args.host, service["url"], service["url"])
)
config = pickle.loads(wcs_config.stdout)
database = config["postgresql"]["database"]
except (KeyError, subprocess.CalledProcessError):
database = None
else:
database = service["name"]
# TODO maybe /tenants/ pour wcs
path = "/var/lib/%s/tenants" % service["name"]
return dict(service, database=database, path=path)
def get_host_info():
if os.path.isfile("%s/data" % host_folder) and not args.update:
return
if not os.path.isdir(host_folder):
os.makedirs(host_folder)
run("scp bin/list_tenants.py hobo.%s:" % args.host)
output = run(
"ssh hobo.%s 'sudo -u hobo HOME=$HOME hobo-manage tenant_command "
"runscript ~/list_tenants.py --all-tenants'" % args.host
)
tenants = []
for line in output.stdout.decode().split("\n"):
if line:
tenant = json.loads(line)
for i, service in enumerate(tenant["services"]):
tenant["services"][i] = parse_service(service)
tenants.append(tenant)
with open("%s/data" % host_folder, "w") as fh:
fh.write(json.dumps(tenants, indent=4))
def get_tenant_info(tenant_name):
with open("%s/data" % host_folder) as fh:
hobos = json.loads(fh.read())
tenant_infos = [x for x in hobos if x["name"] == tenant_name]
if not len(tenant_infos) == 1:
raise(Exception('tenant not found'))
return tenant_infos[0]
def invalidate(tenant_name):
tenant_info = get_tenant_info(tenant_name)
import pdb; pdb.set_trace()
# for service in tenant_info['services']:
# bpath = "%s/%s" % (service['path'], service['url'])
# run('ssh %s.%s sudo mv %s %s.invalid' % (service['name'], args.host, bpath, bpath))
if __name__ == "__main__":
if args.action == "tenantinfo":
get_host_info()
print(json.dumps(get_tenant_info(args.tenant), indent=4))
elif args.action == "tenanturls":
print(' '.join([x['url'] for x in get_tenant_info(args.tenant)['services']]))
elif args.action == "dump":
get_host_info()
tenant = get_tenant_info(args.tenant)
dump_tenant_databases(tenant)
dump_tenant_files(tenant)
elif args.action == "restore":
tenant = get_tenant_info(args.tenant)
#restore_tenant_files(tenant)
#restore_tenant_databases(tenant)
elif args.action == "invalidate":
invalidate(args.tenant)

View File

View File

@ -1,6 +1,6 @@
#!/usr/bin/python3
import json
from urllib.parse import urlparse, urlsplit
from urllib.parse import urlsplit
from hobo.environment.models import AVAILABLE_SERVICES
from hobo.multitenant.middleware import TenantMiddleware
from django.db import connection

View File

@ -0,0 +1,199 @@
#!/usr/bin/python3
import argparse
import json
import os
import pickle
import subprocess
class PublikDump():
def __init__(self, host, hobo_tenant, update=False, target=None, dbtarget=None):
self.host = host
self.hobo_tenant = hobo_tenant
self.update = update
self.target = target
self.dbtarget = dbtarget
self.host_folder = "output/%s" % host
@classmethod
def run(cls, cmd):
print("+ %s" % cmd)
return subprocess.run(cmd, shell=True, check=True, stdout=subprocess.PIPE)
def get_host_info(self):
host_path = "%s/data" % self.host_folder
if os.path.isfile(host_path) and not self.update:
return json.load(open(host_path))
if not os.path.isdir(self.host_folder):
os.makedirs(self.host_folder)
self.run("scp publik_dump/list_tenants.py hobo.%s:" % self.host)
output = self.run(
"ssh hobo.%s 'sudo -u hobo HOME=$HOME hobo-manage tenant_command "
"runscript ~/list_tenants.py --all-tenants'" % self.host
)
tenants = []
for line in output.stdout.decode().split("\n"):
if line:
tenant_infos = json.loads(line)
tenants.append(tenant_infos)
json.dump(tenants, open(host_path, "w"), indent=4)
return tenants
def parse_service(self, service):
if service["name"] == "authentic":
path = "/var/lib/authentic2-multitenant/tenants"
database = "authentic2_multitenant"
elif service["name"] == "wcs":
try:
wcs_config = self.run(
"ssh wcs.%s 'cat /var/lib/wcs/%s/config.pck'"
% (self.host, service["url"])
)
path = "/var/lib/wcs"
except (KeyError, subprocess.CalledProcessError):
wcs_config = self.run(
"ssh wcs.%s 'cat /var/lib/wcs/tenants/%s/config.pck'"
% (self.host, service["url"])
)
path = "/var/lib/wcs/tenants"
config = pickle.loads(wcs_config.stdout)
database = config["postgresql"]["database"]
else:
path = "/var/lib/%s/tenants" % service["name"]
database = service["name"]
return dict(service, database=database, path=path)
def get_tenant_info(self):
tenant_path = '%s/%s.json' % (self.host_folder, self.hobo_tenant)
if os.path.isfile(tenant_path) and not self.update:
return json.load(open(tenant_path))
hobos = self.get_host_info()
tenants = [x for x in hobos if x["name"] == self.hobo_tenant]
if not len(tenants) == 1:
raise(Exception('tenant not found'))
tenant = tenants[0]
for service in tenant['services']:
service.update(self.parse_service(service))
json.dump(tenant, open(tenant_path, "w"), indent=4)
return tenant
def get_dump_folder(self, service):
dump_folder = "%s/%s" % (self.host_folder, service["url"])
if not os.path.isdir(dump_folder):
os.mkdir(dump_folder)
return dump_folder
def dump_tenant_files(self):
tenant = self.get_tenant_info()
for service in tenant["services"]:
dump_folder = self.get_dump_folder(service)
output = "%s/%s.tar.xz" % (dump_folder, service["url"])
self.run(
"ssh %s.%s 'sudo tar -C %s -Jcf - %s' > %s"
% (service["name"], self.host, service["path"], service["url"], output)
)
def restore_tenant_files(self):
tenant = self.get_tenant_info()
assert self.run("ssh %s hostname -f" % self.target).stdout.decode().strip() == self.target
for service in tenant["services"]:
dump_folder = self.get_dump_folder(service)
input_file = "%s/%s.tar.xz" % (dump_folder, service["url"])
self.run(
"cat %s | ssh %s.%s 'sudo tar -C %s -Jxf -'"
% (input_file, service["name"], self.target, service["path"])
)
def dump_tenant_databases(self):
# node2.test.saas.entrouvert.org -> db2.test.saas.entrouvert.org
domain = '.'.join(self.host.split('.')[1:])
tenant = self.get_tenant_info()
for service in tenant["services"]:
dump_folder = self.get_dump_folder(service)
if service["name"] == "wcs":
dump_file = "%s/%s.sql.gz" % (dump_folder, service["database"])
self.run(
"ssh db2.%s 'sudo -u postgres pg_dump -Fc %s' > %s"
% (domain, service["database"], dump_file)
)
else:
dump_file = "%s/%s.sql.gz" % (dump_folder, service["schema"])
self.run(
"ssh db2.%s 'sudo -u postgres pg_dump -n %s -Fc %s' > %s"
% (domain, service["schema"], service["database"], dump_file)
)
def restore_tenant_databases(self):
assert self.run("ssh %s hostname -f" % self.dbtarget).stdout.decode().strip() == self.dbtarget
tenant = self.get_tenant_info()
for service in tenant["services"]:
dump_folder = self.get_dump_folder(service)
if service["name"] == "wcs":
dump_file = "%s/%s.sql.gz" % (dump_folder, service["database"])
self.run(
"ssh %s 'sudo -u postgres dropdb --if-exists %s'"
% (self.dbtarget, service["database"])
)
self.run(
"""ssh %s 'sudo -u postgres createdb %s --owner wcs --template="template0" --lc-collate=fr_FR.utf8 --lc-ctype=fr_FR.utf8'"""
% (self.dbtarget, service["database"])
)
self.run(
"cat %s | ssh %s 'sudo -u postgres pg_restore -d %s'"
% (dump_file, self.dbtarget, service["database"])
)
else:
dump_file = "%s/%s.sql.gz" % (dump_folder, service["schema"])
self.run(
"""ssh %s 'sudo -u postgres psql -c "drop schema if exists %s cascade" %s'"""
% (self.dbtarget, service["schema"], service["database"])
)
self.run(
"cat %s | ssh %s 'sudo -u postgres pg_restore -d %s'"
% (dump_file, self.dbtarget, service["database"])
)
def invalidate_tenant(self):
tenant = self.get_tenant_info()
for service in tenant['services']:
bpath = "%s/%s" % (service['path'], service['url'])
self.run('ssh %s.%s sudo mv %s %s.invalid' % (service['name'], self.host, bpath, bpath))
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("action", default="dump", choices=["tenantinfo", "tenanturls", "dump", "restore", "invalidate"])
parser.add_argument("host", help="origin host")
parser.add_argument("hobo_tenant", help="hobo tenant url")
parser.add_argument("--update", action="store_true")
parser.add_argument("--target", help="destination host")
parser.add_argument("--dbtarget", help="destination host")
args = parser.parse_args()
publik_dump = PublikDump(
host=args.host,
hobo_tenant=args.hobo_tenant,
update=args.update,
target=args.target,
dbtarget=args.dbtarget,
)
if args.action == "tenantinfo":
print(json.dumps(publik_dump.get_tenant_info(), indent=4))
elif args.action == "tenanturls":
print(' '.join([x['url'] for x in publik_dump.get_tenant_info()['services']]))
elif args.action == "dump":
publik_dump.dump_tenant_databases()
publik_dump.dump_tenant_files()
elif args.action == "restore":
publik_dump.restore_tenant_files()
publik_dump.restore_tenant_databases()
elif args.action == "invalidate":
publik_dump.invalidate_tenant()

View File

Binary file not shown.

View File

@ -0,0 +1,3 @@
{"name": "hobo-eurelien.test.entrouvert.org", "services": [{"name": "hobo", "url": "hobo-eurelien.test.entrouvert.org", "schema": "hobo_eurelien_test_entrouvert_org"}, {"name": "authentic", "url": "connexion-eurelien.test.entrouvert.org", "schema": "connexion_eurelien_test_entrouvert_org"}, {"name": "wcs", "url": "demarches-eurelien.test.entrouvert.org", "schema": "wcs_demarches_eurelien_test_entrouvert_org"}, {"name": "passerelle", "url": "passerelle-eurelien.test.entrouvert.org", "schema": "passerelle_eurelien_test_entrouvert_org"}, {"name": "combo", "url": "agents-eurelien.test.entrouvert.org", "schema": "agents_eurelien_test_entrouvert_org"}, {"name": "combo", "url": "portail-eurelien.test.entrouvert.org", "schema": "portail_eurelien_test_entrouvert_org"}, {"name": "fargo", "url": "portedoc-eurelien.test.entrouvert.org", "schema": "portedoc_eurelien_test_entrouvert_org"}, {"name": "chrono", "url": "agendas-eurelien.test.entrouvert.org", "schema": "agendas_eurelien_test_entrouvert_org"}, {"name": "bijoe", "url": "statistiques-eurelien.test.entrouvert.org", "schema": "statistiques_eurelien_test_entrouvert_org"}]}
{"name": "hobo-tours-ville.test.entrouvert.org", "services": [{"name": "hobo", "url": "hobo-tours-ville.test.entrouvert.org", "schema": "hobo_tours_ville_test_entrouvert_org"}, {"name": "authentic", "url": "connexion-tours.test.entrouvert.org", "secondary": true, "schema": "connexion_tours_test_entrouvert_org"}, {"name": "wcs", "url": "demarches-tours.test.entrouvert.org", "secondary": true, "schema": "wcs_demarches_tours_test_entrouvert_org"}, {"name": "wcs", "url": "demarches-tours-ville.test.entrouvert.org", "schema": "wcs_demarches_tours_ville_test_entrouvert_org"}, {"name": "passerelle", "url": "passerelle-tours.test.entrouvert.org", "secondary": true, "schema": "passerelle_tours_test_entrouvert_org"}, {"name": "passerelle", "url": "passerelle-tours-ville.test.entrouvert.org", "schema": "passerelle_tours_ville_test_entrouvert_org"}, {"name": "combo", "url": "agents-tours-ville.test.entrouvert.org", "schema": "agents_tours_ville_test_entrouvert_org"}, {"name": "combo", "url": "agents-tours.test.entrouvert.org", "secondary": true, "schema": "agents_tours_test_entrouvert_org"}, {"name": "combo", "url": "tours.test.entrouvert.org", "secondary": true, "schema": "tours_test_entrouvert_org"}, {"name": "combo", "url": "tours-ville.test.entrouvert.org", "schema": "tours_ville_test_entrouvert_org"}, {"name": "fargo", "url": "portedoc-tours-ville.test.entrouvert.org", "schema": "portedoc_tours_ville_test_entrouvert_org"}, {"name": "fargo", "url": "portedoc-tours.test.entrouvert.org", "secondary": true, "schema": "portedoc_tours_test_entrouvert_org"}, {"name": "chrono", "url": "agendas-tours.test.entrouvert.org", "secondary": true, "schema": "agendas_tours_test_entrouvert_org"}, {"name": "chrono", "url": "agendas-tours-ville.test.entrouvert.org", "schema": "agendas_tours_ville_test_entrouvert_org"}, {"name": "bijoe", "url": "statistiques-tours.test.entrouvert.org", "secondary": true, "schema": "statistiques_tours_test_entrouvert_org"}, {"name": "bijoe", "url": "stats-tours-ville.test.entrouvert.org", "schema": "stats_tours_ville_test_entrouvert_org"}, {"name": "hobo", "url": "hobo-tours.test.entrouvert.org", "secondary": true, "schema": "hobo_tours_test_entrouvert_org"}]}
{"name": "hobo-tours.test.entrouvert.org", "services": [{"name": "hobo", "url": "hobo-tours.test.entrouvert.org", "schema": "hobo_tours_test_entrouvert_org"}, {"name": "authentic", "url": "connexion-tours.test.entrouvert.org", "schema": "connexion_tours_test_entrouvert_org"}, {"name": "wcs", "url": "demarches-tours.test.entrouvert.org", "schema": "wcs_demarches_tours_test_entrouvert_org"}, {"name": "wcs", "url": "demarches-tours-ville.test.entrouvert.org", "secondary": true, "schema": "wcs_demarches_tours_ville_test_entrouvert_org"}, {"name": "passerelle", "url": "passerelle-tours.test.entrouvert.org", "schema": "passerelle_tours_test_entrouvert_org"}, {"name": "passerelle", "url": "passerelle-tours-ville.test.entrouvert.org", "secondary": true, "schema": "passerelle_tours_ville_test_entrouvert_org"}, {"name": "combo", "url": "agents-tours.test.entrouvert.org", "schema": "agents_tours_test_entrouvert_org"}, {"name": "combo", "url": "agents-tours-ville.test.entrouvert.org", "secondary": true, "schema": "agents_tours_ville_test_entrouvert_org"}, {"name": "combo", "url": "tours.test.entrouvert.org", "schema": "tours_test_entrouvert_org"}, {"name": "combo", "url": "tours-ville.test.entrouvert.org", "secondary": true, "schema": "tours_ville_test_entrouvert_org"}, {"name": "fargo", "url": "portedoc-tours-ville.test.entrouvert.org", "secondary": true, "schema": "portedoc_tours_ville_test_entrouvert_org"}, {"name": "fargo", "url": "portedoc-tours.test.entrouvert.org", "schema": "portedoc_tours_test_entrouvert_org"}, {"name": "chrono", "url": "agendas-tours.test.entrouvert.org", "schema": "agendas_tours_test_entrouvert_org"}, {"name": "chrono", "url": "agendas-tours-ville.test.entrouvert.org", "secondary": true, "schema": "agendas_tours_ville_test_entrouvert_org"}, {"name": "bijoe", "url": "statistiques-tours.test.entrouvert.org", "schema": "statistiques_tours_test_entrouvert_org"}, {"name": "bijoe", "url": "stats-tours-ville.test.entrouvert.org", "secondary": true, "schema": "stats_tours_ville_test_entrouvert_org"}, {"name": "hobo", "url": "hobo-tours-ville.test.entrouvert.org", "schema": "hobo_tours_ville_test_entrouvert_org"}]}

31
publik-dump/tests/test.py Normal file
View File

@ -0,0 +1,31 @@
import pytest
import os
from publik_dump.publik_dump import PublikDump
@pytest.fixture
def output(tmpdir):
return str(tmpdir)
@pytest.fixture
def service():
return ""
@pytest.fixture
def publik_dump():
return PublikDump
def test_get_dump_folder(output, publik_dump, service):
#filename = os.path.join(str(tmpdir), 'file.tar')
assert publik_dump.coucou() == "nico"
def test_dump_tenant_files():
print("coucou")
# patch run
def get_host_info():
pass

View File

@ -0,0 +1,343 @@
import json
import mock
import os
import pytest
from subprocess import CalledProcessError
from publik_dump.publik_dump import PublikDump
HOST_INFO_0 = {
"name": "hobo-eurelien.test.entrouvert.org",
"services": [
{
"name": "hobo",
"url": "hobo-eurelien.test.entrouvert.org",
"schema": "hobo_eurelien_test_entrouvert_org"
},
{
"name": "authentic",
"url": "connexion-eurelien.test.entrouvert.org",
"schema": "connexion_eurelien_test_entrouvert_org"
},
{
"name": "wcs",
"url": "demarches-eurelien.test.entrouvert.org",
"schema": "wcs_demarches_eurelien_test_entrouvert_org"
},
{
"name": "passerelle",
"url": "passerelle-eurelien.test.entrouvert.org",
"schema": "passerelle_eurelien_test_entrouvert_org"
},
{
"name": "combo",
"url": "agents-eurelien.test.entrouvert.org",
"schema": "agents_eurelien_test_entrouvert_org"
},
{
"name": "combo",
"url": "portail-eurelien.test.entrouvert.org",
"schema": "portail_eurelien_test_entrouvert_org"
},
{
"name": "fargo",
"url": "portedoc-eurelien.test.entrouvert.org",
"schema": "portedoc_eurelien_test_entrouvert_org"
},
{
"name": "chrono",
"url": "agendas-eurelien.test.entrouvert.org",
"schema": "agendas_eurelien_test_entrouvert_org"
},
{
"name": "bijoe",
"url": "statistiques-eurelien.test.entrouvert.org",
"schema": "statistiques_eurelien_test_entrouvert_org"
}
]
}
HOST_INFO_0_HOBO = HOST_INFO_0['services'][0]
HOST_INFO_0_AUTHENTIC = HOST_INFO_0['services'][1]
HOST_INFO_0_WCS = HOST_INFO_0['services'][2]
TENANT_INFO = {
"name": "hobo-eurelien.test.entrouvert.org",
"services": [
{
"name": "hobo",
"url": "hobo-eurelien.test.entrouvert.org",
"schema": "hobo_eurelien_test_entrouvert_org",
"database": "hobo",
"path": "/var/lib/hobo/tenants"
},
{
"name": "authentic",
"url": "connexion-eurelien.test.entrouvert.org",
"schema": "connexion_eurelien_test_entrouvert_org",
"database": "authentic2_multitenant",
"path": "/var/lib/authentic2-multitenant/tenants"
},
{
"name": "wcs",
"url": "demarches-eurelien.test.entrouvert.org",
"schema": "wcs_demarches_eurelien_test_entrouvert_org",
"database": "wcs_demarches_eurelien_test_entrouvert_org",
"path": "/var/lib/wcs"
},
{
"name": "passerelle",
"url": "passerelle-eurelien.test.entrouvert.org",
"schema": "passerelle_eurelien_test_entrouvert_org",
"database": "passerelle",
"path": "/var/lib/passerelle/tenants"
},
{
"name": "combo",
"url": "agents-eurelien.test.entrouvert.org",
"schema": "agents_eurelien_test_entrouvert_org",
"database": "combo",
"path": "/var/lib/combo/tenants"
},
{
"name": "combo",
"url": "portail-eurelien.test.entrouvert.org",
"schema": "portail_eurelien_test_entrouvert_org",
"database": "combo",
"path": "/var/lib/combo/tenants"
},
{
"name": "fargo",
"url": "portedoc-eurelien.test.entrouvert.org",
"schema": "portedoc_eurelien_test_entrouvert_org",
"database": "fargo",
"path": "/var/lib/fargo/tenants"
},
{
"name": "chrono",
"url": "agendas-eurelien.test.entrouvert.org",
"schema": "agendas_eurelien_test_entrouvert_org",
"database": "chrono",
"path": "/var/lib/chrono/tenants"
},
{
"name": "bijoe",
"url": "statistiques-eurelien.test.entrouvert.org",
"schema": "statistiques_eurelien_test_entrouvert_org",
"database": "bijoe",
"path": "/var/lib/bijoe/tenants"
}
]
}
TENANT_HOBO = TENANT_INFO['services'][0]
TENANT_AUTHENTIC = TENANT_INFO['services'][1]
TENANT_WCS = TENANT_INFO['services'][2]
TARGET = 'node1.test-hds.saas.entrouvert'
DB_TARGET = 'sql3.test-hds.saas.entrouvert'
@pytest.fixture
def publik_dump(tmpdir):
obj = PublikDump('node2.test.saas.entrouvert.org', 'hobo-eurelien.test.entrouvert.org')
obj.host_folder = str(tmpdir)
#obj.run = lambda x: x
return obj
class MockedCompletedProcess():
'''simulate subprocess.run return'''
def __init__(self, stdout):
self.stdout = stdout
def test_run(publik_dump):
with mock.patch('publik_dump.publik_dump.subprocess.run') as mocked_run:
mocked_run.return_value = MockedCompletedProcess('foo result')
output = publik_dump.run('foo query')
assert mocked_run.mock_calls[0][1][0] == 'foo query'
assert output.stdout == 'foo result'
def get_list_tenants():
with open(os.path.join(os.path.dirname(__file__), 'list_tenants.json'), 'rb') as desc:
return desc.read()
def get_config_pck():
with open(os.path.join(os.path.dirname(__file__), 'config.pck'), 'rb') as desc:
return desc.read()
@mock.patch('publik_dump.publik_dump.subprocess.run', return_value=MockedCompletedProcess(get_list_tenants()))
def test_get_host_info(mocked_run, publik_dump):
tenants = publik_dump.get_host_info()
assert len(mocked_run.mock_calls) == 2
assert mocked_run.mock_calls[0][1][0] == \
'scp publik_dump/list_tenants.py hobo.node2.test.saas.entrouvert.org:'
assert mocked_run.mock_calls[1][1][0] == \
"ssh hobo.node2.test.saas.entrouvert.org"\
" 'sudo -u hobo HOME=$HOME hobo-manage tenant_command runscript ~/list_tenants.py --all-tenants'"
assert tenants[0] == HOST_INFO_0
# result from cache
tenants = publik_dump.get_host_info()
assert len(mocked_run.mock_calls) == 2
assert tenants[0] == HOST_INFO_0
# renew cache
publik_dump.update = True
tenants = publik_dump.get_host_info()
assert len(mocked_run.mock_calls) == 4
assert tenants[0] == HOST_INFO_0
def test_parse_service(publik_dump):
# hobo
assert publik_dump.parse_service(HOST_INFO_0_HOBO) == TENANT_HOBO
# authentic
assert publik_dump.parse_service(HOST_INFO_0_AUTHENTIC) == TENANT_AUTHENTIC
# wcs old tenant directory
with mock.patch('publik_dump.publik_dump.subprocess.run') as mocked_run:
mocked_run.return_value = MockedCompletedProcess(get_config_pck())
assert publik_dump.parse_service(HOST_INFO_0_WCS) == TENANT_WCS
# wcs new tenant directory
with mock.patch('publik_dump.publik_dump.subprocess.run') as mocked_run:
mocked_run.side_effect = [CalledProcessError(1, ''), MockedCompletedProcess(get_config_pck())]
result = publik_dump.parse_service(HOST_INFO_0_WCS)
assert result['path'] == '/var/lib/wcs/tenants'
@mock.patch('publik_dump.publik_dump.subprocess.run', return_value=MockedCompletedProcess(get_config_pck()))
@mock.patch('publik_dump.publik_dump.PublikDump.get_host_info', return_value=[HOST_INFO_0])
def test_get_tenant_info(mocked_get_host_info, mocked_run, publik_dump):
tenant = publik_dump.get_tenant_info()
assert len(mocked_run.mock_calls) == 1
assert tenant == TENANT_INFO
# result from cache
tenant = publik_dump.get_tenant_info()
assert len(mocked_run.mock_calls) == 1
assert tenant == TENANT_INFO
# renew cache
publik_dump.update = True
tenant = publik_dump.get_tenant_info()
assert tenant == TENANT_INFO
def test_get_dump_folder(publik_dump):
service = HOST_INFO_0_HOBO
assert publik_dump.get_dump_folder(service).strip('/').split('/')[0] == 'tmp'
assert publik_dump.get_dump_folder(service).strip('/').split('/')[-1] == service['url']
@mock.patch('publik_dump.publik_dump.subprocess.run')
@mock.patch('publik_dump.publik_dump.PublikDump.get_tenant_info', return_value=TENANT_INFO)
def test_dump_tenant_files(mocked_tenant_info, mocked_run, publik_dump):
publik_dump.dump_tenant_files()
assert len(mocked_run.mock_calls) == 9
# hobo
assert mocked_run.mock_calls[0][1][0].replace(publik_dump.host_folder, 'HF') == \
"ssh hobo.node2.test.saas.entrouvert.org '" \
"sudo tar -C /var/lib/hobo/tenants -Jcf - hobo-eurelien.test.entrouvert.org" \
"' > HF/hobo-eurelien.test.entrouvert.org/hobo-eurelien.test.entrouvert.org.tar.xz"
# authentic
assert mocked_run.mock_calls[1][1][0].replace(publik_dump.host_folder, 'HF') == \
"ssh authentic.node2.test.saas.entrouvert.org '"\
"sudo tar -C /var/lib/authentic2-multitenant/tenants -Jcf - connexion-eurelien.test.entrouvert.org" \
"' > HF/connexion-eurelien.test.entrouvert.org/connexion-eurelien.test.entrouvert.org.tar.xz"
# wcs
assert mocked_run.mock_calls[2][1][0].replace(publik_dump.host_folder, 'HF') == \
"ssh wcs.node2.test.saas.entrouvert.org '" \
"sudo tar -C /var/lib/wcs -Jcf - demarches-eurelien.test.entrouvert.org" \
"' > HF/demarches-eurelien.test.entrouvert.org/demarches-eurelien.test.entrouvert.org.tar.xz"
@mock.patch('publik_dump.publik_dump.subprocess.run', return_value=MockedCompletedProcess(TARGET.encode()))
@mock.patch('publik_dump.publik_dump.PublikDump.get_tenant_info', return_value=TENANT_INFO)
def test_restore_tenant_files(mocked_tenant_info, mocked_run, publik_dump):
publik_dump.target = TARGET
publik_dump.restore_tenant_files()
assert len(mocked_run.mock_calls) == 1 + 9
assert mocked_run.mock_calls[0][1][0] == \
'ssh node1.test-hds.saas.entrouvert hostname -f'
# hobo
assert mocked_run.mock_calls[1][1][0].replace(publik_dump.host_folder, 'HF') == \
"cat HF/hobo-eurelien.test.entrouvert.org/hobo-eurelien.test.entrouvert.org.tar.xz"\
" | ssh hobo.node1.test-hds.saas.entrouvert"\
" 'sudo tar -C /var/lib/hobo/tenants -Jxf -'"
# authentic
assert mocked_run.mock_calls[2][1][0].replace(publik_dump.host_folder, 'HF') == \
"cat HF/connexion-eurelien.test.entrouvert.org/connexion-eurelien.test.entrouvert.org.tar.xz"\
" | ssh authentic.node1.test-hds.saas.entrouvert"\
" 'sudo tar -C /var/lib/authentic2-multitenant/tenants -Jxf -'"
# wcs
assert mocked_run.mock_calls[3][1][0].replace(publik_dump.host_folder, 'HF') == \
"cat HF/demarches-eurelien.test.entrouvert.org/demarches-eurelien.test.entrouvert.org.tar.xz"\
" | ssh wcs.node1.test-hds.saas.entrouvert"\
" 'sudo tar -C /var/lib/wcs -Jxf -'"
@mock.patch('publik_dump.publik_dump.subprocess.run')
@mock.patch('publik_dump.publik_dump.PublikDump.get_tenant_info', return_value=TENANT_INFO)
def test_dump_tenant_databases(mocked_tenant_info, mocked_run, publik_dump):
publik_dump.dump_tenant_databases()
assert len(mocked_run.mock_calls) == 9
# hobo
assert mocked_run.mock_calls[0][1][0].replace(publik_dump.host_folder, 'HF') == \
"ssh db2.test.saas.entrouvert.org"\
" 'sudo -u postgres pg_dump -n hobo_eurelien_test_entrouvert_org -Fc hobo'"\
" > HF/hobo-eurelien.test.entrouvert.org/hobo_eurelien_test_entrouvert_org.sql.gz"
# authentic
assert mocked_run.mock_calls[1][1][0].replace(publik_dump.host_folder, 'HF') == \
"ssh db2.test.saas.entrouvert.org"\
" 'sudo -u postgres pg_dump -n connexion_eurelien_test_entrouvert_org -Fc authentic2_multitenant'"\
" > HF/connexion-eurelien.test.entrouvert.org/connexion_eurelien_test_entrouvert_org.sql.gz"
# wcs
assert mocked_run.mock_calls[2][1][0].replace(publik_dump.host_folder, 'HF') == \
"ssh db2.test.saas.entrouvert.org"\
" 'sudo -u postgres pg_dump -Fc wcs_demarches_eurelien_test_entrouvert_org'"\
" > HF/demarches-eurelien.test.entrouvert.org/wcs_demarches_eurelien_test_entrouvert_org.sql.gz"
@mock.patch('publik_dump.publik_dump.subprocess.run', return_value=MockedCompletedProcess(DB_TARGET.encode()))
@mock.patch('publik_dump.publik_dump.PublikDump.get_tenant_info', return_value=TENANT_INFO)
def test_restore_tenant_database(mocked_tenant_info, mocked_run, publik_dump):
publik_dump.dbtarget = DB_TARGET
publik_dump.restore_tenant_databases()
assert len(mocked_run.mock_calls) == 1 + 3 + 2*8
assert mocked_run.mock_calls[0][1][0] == \
'ssh sql3.test-hds.saas.entrouvert hostname -f'
# hobo
assert mocked_run.mock_calls[1][1][0].replace(publik_dump.host_folder, 'HF') == \
"ssh sql3.test-hds.saas.entrouvert"\
" 'sudo -u postgres psql -c \"drop schema if exists hobo_eurelien_test_entrouvert_org cascade\""\
" hobo'"
assert mocked_run.mock_calls[2][1][0].replace(publik_dump.host_folder, 'HF') == \
"cat HF/hobo-eurelien.test.entrouvert.org/hobo_eurelien_test_entrouvert_org.sql.gz"\
" | ssh sql3.test-hds.saas.entrouvert 'sudo -u postgres pg_restore -d hobo'"
# wcs
assert mocked_run.mock_calls[5][1][0].replace(publik_dump.host_folder, 'HF') == \
"ssh sql3.test-hds.saas.entrouvert"\
" 'sudo -u postgres dropdb --if-exists wcs_demarches_eurelien_test_entrouvert_org'"
assert mocked_run.mock_calls[6][1][0].replace(publik_dump.host_folder, 'HF') == \
"ssh sql3.test-hds.saas.entrouvert"\
" 'sudo -u postgres createdb wcs_demarches_eurelien_test_entrouvert_org"\
" --owner wcs --template=\"template0\" --lc-collate=fr_FR.utf8 --lc-ctype=fr_FR.utf8'"
assert mocked_run.mock_calls[7][1][0].replace(publik_dump.host_folder, 'HF') == \
"cat HF/demarches-eurelien.test.entrouvert.org/wcs_demarches_eurelien_test_entrouvert_org.sql.gz"\
" | ssh sql3.test-hds.saas.entrouvert"\
" 'sudo -u postgres pg_restore -d wcs_demarches_eurelien_test_entrouvert_org'"