mirror of
https://github.com/fluencelabs/node-distro
synced 2025-04-24 23:12:13 +00:00
190 lines
5.4 KiB
Python
190 lines
5.4 KiB
Python
from __future__ import with_statement
|
|
from collections import namedtuple
|
|
from fabric.api import *
|
|
from fabric.contrib.files import append
|
|
from utils import *
|
|
from compose import *
|
|
from collections import namedtuple
|
|
from time import sleep
|
|
|
|
|
|
# DTOs
|
|
Node = namedtuple("Node", "peer_id tcp ws")
|
|
Service = namedtuple("Service", "port multiaddr")
|
|
|
|
FLUENCE_NODE_PORT = "7777"
|
|
FLUENCE_CLIENT_PORT = "9999"
|
|
PEER_ID_MARKER = "server peer id"
|
|
|
|
|
|
@task
|
|
@runs_once
|
|
def deploy_fluence():
|
|
# 'running', 'output'
|
|
with hide():
|
|
load_config()
|
|
target = target_environment()
|
|
env.hosts = target["bootstrap"]
|
|
|
|
puts("Fluence: deploying bootstrap")
|
|
results = execute(deploy_bootstrap)
|
|
bootstraps = fill_addresses(results.items())
|
|
bootstrap = bootstraps[0]
|
|
env.bootstraps = map(lambda b: b.tcp.multiaddr, bootstraps)
|
|
|
|
|
|
env.hosts = target["hosts"]
|
|
puts("Fluence: deploying rest of the nodes")
|
|
results = execute(deploy_nodes)
|
|
nodes = fill_addresses(results.items())
|
|
|
|
puts("Fluence: deployed.\nAddresses:\n%s" % "\n".join(
|
|
"{} {} {}".format(n.tcp.multiaddr, n.ws.multiaddr, n.peer_id) for n in nodes))
|
|
puts("Bootstrap:\n%s" % "\n".join(
|
|
"{} {} {}".format(n.tcp.multiaddr, n.ws.multiaddr, n.peer_id) for n in bootstraps))
|
|
|
|
|
|
@task
|
|
@parallel
|
|
def deploy_bootstrap():
|
|
target = target_environment()
|
|
yml = "fluence_bootstrap.yml"
|
|
keypair = get_keypairs(yml, get_host_idx(containers=1), count=1)
|
|
gen_compose_file(
|
|
out=yml,
|
|
container_image=target['container_image'],
|
|
scale=1,
|
|
is_bootstrap=True,
|
|
bootstraps=target['external_bootstraps'],
|
|
host=env.host_string,
|
|
management_key=target['management_key'],
|
|
keypairs=keypair,
|
|
ceramic_host=target['ceramic_host'],
|
|
)
|
|
|
|
return do_deploy_fluence(yml)
|
|
|
|
|
|
@task
|
|
@parallel
|
|
def deploy_nodes():
|
|
target = target_environment()
|
|
|
|
yml = "fluence.yml"
|
|
scale = target["containers_per_host"]
|
|
keypairs = get_keypairs(yml, get_host_idx(scale), count=scale)
|
|
gen_compose_file(
|
|
out=yml,
|
|
container_image=target['container_image'],
|
|
scale=scale,
|
|
is_bootstrap=False,
|
|
bootstraps=env.bootstraps + target['external_bootstraps'],
|
|
host=env.host_string,
|
|
management_key=target['management_key'],
|
|
keypairs=keypairs,
|
|
ceramic_host=target['ceramic_host'],
|
|
)
|
|
|
|
return do_deploy_fluence(yml)
|
|
|
|
|
|
@task
|
|
@parallel
|
|
# returns {ip: Node}
|
|
def do_deploy_fluence(yml="fluence.yml"):
|
|
with hide():
|
|
compose("pull -q", yml)
|
|
compose('rm -fs', yml)
|
|
compose('up --no-start', yml) # was: 'create'
|
|
copy_configs(yml)
|
|
compose("restart", yml)
|
|
sleep(5)
|
|
addrs = get_fluence_addresses(yml)
|
|
return addrs
|
|
|
|
|
|
def get_host_idx(containers):
|
|
return env.hosts.index(env.host_string) * containers
|
|
|
|
def copy_configs(yml):
|
|
# there's no `cp` in `docker-compose`: https://github.com/docker/compose/issues/5523
|
|
put("Config.toml", "./")
|
|
containers = compose('ps -q', yml).splitlines()
|
|
for id in containers:
|
|
run('docker cp ./Config.toml %s:/Config.toml' % id)
|
|
|
|
# returns [Node]
|
|
def get_fluence_addresses(yml="fluence.yml"):
|
|
containers = compose('ps -q', yml).splitlines()
|
|
nodes = []
|
|
for id in containers:
|
|
(tcp_port, ws_port) = get_ports(id)
|
|
peer_id = get_fluence_peer_ids(id)
|
|
node = Node(peer_id=peer_id, tcp=Service(tcp_port, None), ws=Service(ws_port, None))
|
|
nodes.append(node)
|
|
return nodes
|
|
|
|
# Assuming Fluence's tcp port starts with 7
|
|
# and websocket port starts with 9
|
|
def is_fluence_port(host_port):
|
|
is_tcp = '0.0.0.0:7' in host_port
|
|
is_ws = '0.0.0.0:9' in host_port
|
|
return is_tcp or is_ws
|
|
|
|
# returns (tcp port, ws port)
|
|
def get_ports(container):
|
|
from itertools import chain
|
|
lines = run('docker port %s' % container).splitlines()
|
|
ports = chain.from_iterable(l.split('/tcp -> ') for l in lines)
|
|
# filter by host port and remove 0.0.0.0 part
|
|
ports = list(port.replace('0.0.0.0:', '') for port in ports if is_fluence_port(port))
|
|
(a, b) = ports
|
|
# tcp port starts with 7
|
|
if a.startswith('7'):
|
|
return (a, b)
|
|
else:
|
|
return (b, a)
|
|
|
|
|
|
def get_fluence_peer_ids(container, yml="fluence.yml"):
|
|
logs = run('docker logs --tail 10000 %s' % container).splitlines()
|
|
return parse_peer_ids(logs)
|
|
|
|
|
|
# returns (node_peer_id, peer_peer_id)
|
|
def parse_peer_ids(logs):
|
|
def after_eq(line):
|
|
return line.split("=")[-1].strip()
|
|
|
|
peer_id = None
|
|
for line in logs:
|
|
if PEER_ID_MARKER in line:
|
|
peer_id = after_eq(line)
|
|
return peer_id
|
|
|
|
|
|
def compose(cmd, yml="fluence.yml"):
|
|
return run('docker-compose -f %s %s' % (yml, cmd))
|
|
|
|
|
|
def service(yml):
|
|
return yml.replace(".yml", "")
|
|
|
|
|
|
# takes: dict {ip: Node}
|
|
# returns: [Node]
|
|
def fill_addresses(nodes_dict):
|
|
result = []
|
|
for ip, nodes in nodes_dict:
|
|
for node in nodes:
|
|
# node service multiaddr
|
|
node = node._replace(tcp=fill_multiaddr(ip, node.tcp))
|
|
# peer service multiaddr
|
|
node = node._replace(ws=fill_multiaddr(ip, node.ws, suffix="/ws"))
|
|
result.append(node)
|
|
return result
|
|
|
|
|
|
def fill_multiaddr(ip, service, suffix=""):
|
|
return service._replace(multiaddr="/ip4/{}/tcp/{}{}".format(ip, service.port, suffix))
|