From 6b7c059a7c0ca9a31a5c8ab5da42e46fafccb0d2 Mon Sep 17 00:00:00 2001 From: Baohua Yang Date: Tue, 11 Jul 2017 16:04:30 +0800 Subject: [PATCH] [CE-82] Fix fabric 1.0 support bugs * Setup the fabric network using the initialize.sh script; * Fix port mapping conflicts in fabric-ca service; * Fix docker-compose env variables. Change-Id: Ib2135f0d23ec5114f4b25bb6e57328ee8485b859 Signed-off-by: Baohua Yang --- .../fabric-0.6/local/peer-pbft.yml | 4 +- .../fabric-1.0/local/fabric-solo-4.yaml | 8 +- .../fabric-1.0/local/orderer-base.yaml | 12 ++ .../fabric-1.0/local/peer-base.yaml | 20 ++- src/agent/docker/cluster.py | 34 +++-- src/agent/docker/docker_swarm.py | 136 +++++++----------- src/common/__init__.py | 5 +- src/common/fabric_network_config.py | 6 +- src/common/utils.py | 4 +- src/modules/cluster.py | 91 ++++++------ src/modules/host.py | 20 ++- .../static/css/jquery.dataTables.min.css | 2 +- src/themes/basic/templates/cluster_info.html | 9 +- 13 files changed, 180 insertions(+), 171 deletions(-) diff --git a/src/agent/docker/_compose_files/fabric-0.6/local/peer-pbft.yml b/src/agent/docker/_compose_files/fabric-0.6/local/peer-pbft.yml index bd0753c2..33e7de6a 100644 --- a/src/agent/docker/_compose_files/fabric-0.6/local/peer-pbft.yml +++ b/src/agent/docker/_compose_files/fabric-0.6/local/peer-pbft.yml @@ -23,12 +23,12 @@ services: - hyperledger=true - com.docker.swarm.reschedule-policy=["on-node-failure"] environment: + - CORE_LOGGING_LEVEL=${CLUSTER_LOG_LEVEL} #critical, error, warning, notice, info, debug - CORE_PEER_ADDRESSAUTODETECT=true - CORE_PEER_NETWORKID=${PEER_NETWORKID} - - CORE_LOGGING_LEVEL=${CLUSTER_LOG_LEVEL} #critical, error, warning, notice, info, debug + - CORE_PEER_VALIDATOR_CONSENSUS_PLUGIN=${PEER_VALIDATOR_CONSENSUS_PLUGIN} # noops, pbft - CORE_VM_ENDPOINT=${VM_ENDPOINT} - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${VM_DOCKER_HOSTCONFIG_NETWORKMODE} # host, bridge, ipvlan, none - - CORE_PEER_VALIDATOR_CONSENSUS_PLUGIN=${PEER_VALIDATOR_CONSENSUS_PLUGIN} # noops, pbft # The following section enables noops consensus - CORE_NOOPS_BLOCK_TIMEOUT=2 # only useful when in noops - CORE_NOOPS_BLOCK_WAIT=2 # only useful when in noops diff --git a/src/agent/docker/_compose_files/fabric-1.0/local/fabric-solo-4.yaml b/src/agent/docker/_compose_files/fabric-1.0/local/fabric-solo-4.yaml index c47fa8ec..2d5fd35e 100644 --- a/src/agent/docker/_compose_files/fabric-1.0/local/fabric-solo-4.yaml +++ b/src/agent/docker/_compose_files/fabric-1.0/local/fabric-solo-4.yaml @@ -8,13 +8,13 @@ version: '2.0' services: - ca: + ca.example.com: image: hyperledger/fabric-ca container_name: ${COMPOSE_PROJECT_NAME}_fabric-ca hostname: ca # command: /go/src/github.com/hyperledger/fabric-ca/bin/ca server start -ca testdata/ec.pem -ca-key testdata/ec-key.pem -config testdata/testconfig.json - ports: - - "7054:7054" + expose: + - "7054" command: fabric-ca-server start -b admin:adminpw orderer.example.com: # There can be multiple orderers @@ -82,7 +82,7 @@ services: - peer0.org2.example.com - peer1.org2.example.com working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer - command: bash -c 'while true; do sleep 20170504; done' + command: bash -c 'sleep 2; bash ./scripts/initialize.sh; while true; do sleep 20170504; done' networks: default: diff --git a/src/agent/docker/_compose_files/fabric-1.0/local/orderer-base.yaml b/src/agent/docker/_compose_files/fabric-1.0/local/orderer-base.yaml index d1cb138d..91667e28 100644 --- a/src/agent/docker/_compose_files/fabric-1.0/local/orderer-base.yaml +++ b/src/agent/docker/_compose_files/fabric-1.0/local/orderer-base.yaml @@ -9,6 +9,11 @@ version: '2' services: orderer-base: image: hyperledger/fabric-orderer + restart: unless-stopped + labels: + - monitor=true + - hyperledger=true + - com.docker.swarm.reschedule-policy=["on-node-failure"] environment: - ORDERER_GENERAL_LOGLEVEL=DEBUG - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0 @@ -29,4 +34,11 @@ services: - ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt] expose: - "7050" # + mem_limit: 512000000 + memswap_limit: 1000000000 + cpu_quota: 50000 + logging: + driver: json-file + options: + max-size: 100m command: orderer start diff --git a/src/agent/docker/_compose_files/fabric-1.0/local/peer-base.yaml b/src/agent/docker/_compose_files/fabric-1.0/local/peer-base.yaml index e26d4565..366053c6 100644 --- a/src/agent/docker/_compose_files/fabric-1.0/local/peer-base.yaml +++ b/src/agent/docker/_compose_files/fabric-1.0/local/peer-base.yaml @@ -9,11 +9,16 @@ version: '2' services: peer-base: image: hyperledger/fabric-peer + restart: unless-stopped + labels: + - monitor=true + - hyperledger=true + - com.docker.swarm.reschedule-policy=["on-node-failure"] environment: #- CORE_PEER_ID=peer0 - - CORE_PEER_ADDRESSAUTODETECT=false - - CORE_LOGGING_LEVEL=DEBUG - - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=local_default # uncomment this to use specific network + - CORE_LOGGING_LEVEL=${CLUSTER_LOG_LEVEL} #critical, error, warning, notice, info, debug + - CORE_PEER_ADDRESSAUTODETECT=true + - CORE_PEER_NETWORKID=${PEER_NETWORKID} #- CORE_PEER_NETWORKID=dev - CORE_PEER_GOSSIP_USELEADERELECTION=true - CORE_PEER_GOSSIP_ORGLEADER=false # this node is the group leader, default to false @@ -22,6 +27,8 @@ services: - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt + - CORE_VM_ENDPOINT=${VM_ENDPOINT} + - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${VM_DOCKER_HOSTCONFIG_NETWORKMODE} # host, bridge, ipvlan, none expose: - "7050" # Rest - "7051" # Grpc @@ -37,4 +44,11 @@ services: - /var/run/docker.sock:/var/run/docker.sock #volumes: # - /var/run/:/host/var/run/ + mem_limit: 512000000 + memswap_limit: 1000000000 + cpu_quota: 50000 + logging: + driver: json-file + options: + max-size: 100m command: peer node start diff --git a/src/agent/docker/cluster.py b/src/agent/docker/cluster.py index ff2c6af9..d81ee6c4 100644 --- a/src/agent/docker/cluster.py +++ b/src/agent/docker/cluster.py @@ -31,9 +31,7 @@ class ClusterOnDocker(ClusterBase): def __init__(self): pass - def create(self, cid, mapped_ports, host, user_id="", - network_type=NETWORK_TYPES[0], - config=None): + def create(self, cid, mapped_ports, host, config, user_id=""): """ Create a cluster based on given data TODO: maybe need other id generation mechanism @@ -54,7 +52,7 @@ def create(self, cid, mapped_ports, host, user_id="", # start compose project, failed then clean and return logger.debug("Start compose project with name={}".format(cid)) containers = compose_up(name=cid, mapped_ports=mapped_ports, host=host, - network_type=network_type, config=config) + config=config) if not containers: logger.warning("failed to create cluster, with container={}" .format(containers)) @@ -63,23 +61,23 @@ def create(self, cid, mapped_ports, host, user_id="", logger.debug("Created containers={}".format(containers)) return containers - def delete(self, id, worker_api, network_type, config): - return compose_clean(id, worker_api, network_type, config) + def delete(self, id, worker_api, config): + return compose_clean(id, worker_api, config) - def start(self, name, worker_api, mapped_ports, network_type, - log_type, log_level, log_server, config): - return compose_start(name, worker_api, mapped_ports, network_type, - log_type, log_level, log_server, config) + def start(self, name, worker_api, mapped_ports, log_type, log_level, + log_server, config): + return compose_start(name, worker_api, mapped_ports, log_type, + log_level, log_server, config) - def restart(self, name, worker_api, mapped_ports, network_type, - log_type, log_level, log_server, config): - return compose_restart(name, worker_api, mapped_ports, network_type, - log_type, log_level, log_server, config) + def restart(self, name, worker_api, mapped_ports, log_type, log_level, + log_server, config): + return compose_restart(name, worker_api, mapped_ports, log_type, + log_level, log_server, config) - def stop(self, name, worker_api, mapped_ports, network_type, - log_type, log_level, log_server, config): - return compose_stop(name, worker_api, mapped_ports, network_type, - log_type, log_level, log_server, config) + def stop(self, name, worker_api, mapped_ports, log_type, log_level, + log_server, config): + return compose_stop(name, worker_api, mapped_ports, log_type, + log_level, log_server, config) cluster_on_docker = ClusterOnDocker() diff --git a/src/agent/docker/docker_swarm.py b/src/agent/docker/docker_swarm.py index 2ce75eaa..9820e1d8 100644 --- a/src/agent/docker/docker_swarm.py +++ b/src/agent/docker/docker_swarm.py @@ -327,37 +327,34 @@ def get_project(template_path): def _compose_set_env(name, worker_api, mapped_ports=SERVICE_PORTS, - network_type=NETWORK_TYPES[0], log_level=CLUSTER_LOG_LEVEL[0], log_type=CLUSTER_LOG_TYPES[0], log_server="", config=None): envs = { - 'DOCKER_HOST': worker_api, 'COMPOSE_PROJECT_NAME': name, 'CLUSTER_LOG_LEVEL': log_level, - 'NETWORK_TYPES': network_type, + 'CLUSTER_NETWORK': CLUSTER_NETWORK + "_{}".format( + config['consensus_plugin']), + 'DOCKER_HOST': worker_api, + 'PEER_NETWORKID': name, + 'NETWORK_TYPES': config['network_type'], 'VM_ENDPOINT': worker_api, 'VM_DOCKER_HOSTCONFIG_NETWORKMODE': CLUSTER_NETWORK + "_{}".format(config['consensus_plugin']), - 'PEER_NETWORKID': name, } - if network_type == NETWORK_TYPE_FABRIC_V1: + if config['network_type'] == NETWORK_TYPE_FABRIC_V1: envs.update({ 'COMPOSE_FILE': "fabric-{}-{}.yaml".format( config['consensus_plugin'], config['size']), - 'CLUSTER_NETWORK': CLUSTER_NETWORK + "_{}".format( - config['consensus_plugin']), 'COMPOSE_PROJECT_PATH': '/opt/cello/fabric-1.0/local', }) - elif network_type == NETWORK_TYPE_FABRIC_PRE_V1: + elif config['network_type'] == NETWORK_TYPE_FABRIC_PRE_V1: envs.update({ 'COMPOSE_FILE': "fabric-{}.yml".format(config['size']), 'PEER_VALIDATOR_CONSENSUS_PLUGIN': config['consensus_plugin'], 'PBFT_GENERAL_MODE': config['consensus_mode'], 'PBFT_GENERAL_N': str(config['size']), - 'CLUSTER_NETWORK': CLUSTER_NETWORK + "_{}".format( - config['consensus_plugin']), }) os.environ.update(envs) @@ -367,14 +364,12 @@ def _compose_set_env(name, worker_api, mapped_ports=SERVICE_PORTS, os.environ['SYSLOG_SERVER'] = log_server -def compose_up(name, host, mapped_ports, network_type=NETWORK_TYPES[0], - config=None, timeout=5): +def compose_up(name, host, mapped_ports, config=None, timeout=5): """ Compose up a cluster :param name: The name of the cluster :param mapped_ports: The mapped ports list of the cluster :param host: Docker host obj - :param network_type: Fabric version :param config: the blockchain network config :param timeout: Docker client timeout value :return: The name list of the started peer containers @@ -382,25 +377,25 @@ def compose_up(name, host, mapped_ports, network_type=NETWORK_TYPES[0], logger.debug( "Compose start: name={}, host={}, mapped_port={}," - "config={} network_type={}".format( + "config={}".format( name, host.get("name"), mapped_ports, - config.get_data(), network_type)) + config.get_data())) worker_api, log_type, log_server, log_level = \ host.get("worker_api"), host.get("log_type"), host.get("log_server"), \ host.get("log_level") if log_type != CLUSTER_LOG_TYPES[0]: # not local os.environ['SYSLOG_SERVER'] = log_server - _compose_set_env(name, worker_api, mapped_ports, network_type, - log_level, log_type, log_server, config) + _compose_set_env(name, worker_api, mapped_ports, log_level, log_type, + log_server, config) try: - template_path = COMPOSE_FILE_PATH + os.sep + network_type + \ + template_path = COMPOSE_FILE_PATH + os.sep + config['network_type'] + \ os.sep + log_type project = get_project(template_path) containers = project.up(detached=True, timeout=timeout) except Exception as e: - logger.warning("Exception when compose start={}".format(e.message)) + logger.warning("Exception when compose start={}".format(e)) return {} logger.debug("containers={}".format(containers)) if not containers or config['size'] > len(containers): @@ -412,19 +407,18 @@ def compose_up(name, host, mapped_ports, network_type=NETWORK_TYPES[0], return result -def compose_clean(name, worker_api, network_type, config): +def compose_clean(name, worker_api, config): """ Try best to clean a compose project and clean related containers. :param name: name of the project :param worker_api: Docker Host url - :param consensus_plugin: which consensus plugin + :param config: network config :return: True or False """ has_exception = False try: - compose_down(name=name, worker_api=worker_api, - network_type=network_type, config=config) + compose_down(name=name, worker_api=worker_api, config=config) except Exception as e: logger.error("Error in stop compose project, will clean") logger.debug(e) @@ -448,39 +442,31 @@ def compose_clean(name, worker_api, network_type, config): def compose_start(name, worker_api, mapped_ports=SERVICE_PORTS, - network_type=NETWORK_TYPES[0], log_type=CLUSTER_LOG_TYPES[0], log_server="", log_level=CLUSTER_LOG_LEVEL[0], config=None): """ Start the cluster :param name: The name of the cluster - :param mapped_ports: The mapped port list :param worker_api: Docker host daemon - :param network_type: fabric version - :param consensus_plugin: Cluster consensus type - :param consensus_mode: Cluster consensus mode + :param mapped_ports: The mapped port list :param log_type: which log plugin for host :param log_server: syslog server - :param cluster_size: the size of the cluster + :param log_level: level of the logging msg + :param config: network config :return: """ logger.debug("Compose Start {} with worker_api={}, mapped_ports={} " - "network_type={} config={}".format(name, worker_api, - mapped_ports, network_type, - config.get_data())) - - _compose_set_env(name, worker_api, mapped_ports, network_type, - log_level, log_type, log_server, config) + "config={}".format(name, worker_api, + mapped_ports, + config.get_data())) - if network_type == NETWORK_TYPE_FABRIC_PRE_V1: - cluster_version = 'fabric-0.6' - else: - cluster_version = 'fabric-1.0' + _compose_set_env(name, worker_api, mapped_ports, log_level, log_type, + log_server, config) # project = get_project(COMPOSE_FILE_PATH+"/"+consensus_plugin) project = get_project(COMPOSE_FILE_PATH + - "/{}/".format(cluster_version) + log_type) + "/{}/".format(config['network_type']) + log_type) try: project.start() start_containers(worker_api, name + '-') @@ -491,39 +477,30 @@ def compose_start(name, worker_api, mapped_ports=SERVICE_PORTS, def compose_restart(name, worker_api, mapped_ports=SERVICE_PORTS, - network_type=NETWORK_TYPES[0], log_type=CLUSTER_LOG_TYPES[0], log_server="", log_level=CLUSTER_LOG_LEVEL[0], config=None): """ Restart the cluster :param name: The name of the cluster - :param mapped_ports: The mapped port list :param worker_api: Docker host daemon - :param network_type: fabric image version - :param consensus_plugin: Cluster consensus type - :param consensus_mode: Cluster consensus mode + :param mapped_ports: The mapped port list :param log_type: which log plugin for host :param log_server: syslog server - :param cluster_size: the size of the cluster + :param log_level: level of the logging msg + :param config: network config :return: """ logger.debug("Compose restart {} with worker_api={}, mapped_ports={} " - "network_type={} config={}".format(name, worker_api, - mapped_ports, network_type, - config.get_data())) - - _compose_set_env(name, worker_api, mapped_ports, network_type, - log_level, log_type, log_server, config) + "config={}".format(name, worker_api, mapped_ports, + config.get_data())) - if network_type == NETWORK_TYPE_FABRIC_PRE_V1: - cluster_version = 'fabric-0.6' - else: - cluster_version = 'fabric-1.0' + _compose_set_env(name, worker_api, mapped_ports, log_level, log_type, + log_server, config) # project = get_project(COMPOSE_FILE_PATH+"/"+consensus_plugin) - project = get_project(COMPOSE_FILE_PATH + - "/{}/".format(cluster_version) + log_type) + project = get_project(COMPOSE_FILE_PATH + os.sep + config['network_type'] + + os.sep + log_type) try: project.restart() start_containers(worker_api, name + '-') @@ -534,21 +511,18 @@ def compose_restart(name, worker_api, mapped_ports=SERVICE_PORTS, def compose_stop(name, worker_api, mapped_ports=SERVICE_PORTS, - network_type=NETWORK_TYPES[0], log_type=CLUSTER_LOG_TYPES[0], log_server="", log_level=CLUSTER_LOG_LEVEL[0], config=None, timeout=5): """ Stop the cluster :param name: The name of the cluster - :param mapped_ports: The mapped ports list :param worker_api: Docker host daemon - :param network_type: Fabric image version - :param consensus_plugin: Cluster consensus type - :param consensus_mode: Cluster consensus mode + :param mapped_ports: The mapped ports list :param log_type: which log plugin for host :param log_server: syslog server - :param cluster_size: the size of the cluster + :param log_level: level of the logging msg + :param config: network config :param timeout: Docker client timeout :return: """ @@ -558,16 +532,11 @@ def compose_stop(name, worker_api, mapped_ports=SERVICE_PORTS, config.get_data(), log_type)) - _compose_set_env(name, worker_api, mapped_ports, network_type, - log_level, log_type, log_server, config) - - if network_type == NETWORK_TYPE_FABRIC_PRE_V1: - cluster_version = 'fabric-0.6' - else: - cluster_version = 'fabric-1.0' + _compose_set_env(name, worker_api, mapped_ports, log_level, log_type, + log_server, config) - project = get_project(COMPOSE_FILE_PATH + - "/{}/".format(cluster_version) + log_type) + project = get_project(COMPOSE_FILE_PATH + os.sep + config['network_type'] + + os.sep + log_type) try: project.stop(timeout=timeout) except Exception as e: @@ -577,7 +546,6 @@ def compose_stop(name, worker_api, mapped_ports=SERVICE_PORTS, def compose_down(name, worker_api, mapped_ports=SERVICE_PORTS, - network_type=NETWORK_TYPES[0], log_type=CLUSTER_LOG_TYPES[0], log_server="", log_level=CLUSTER_LOG_LEVEL[0], config=None, timeout=5): @@ -586,27 +554,23 @@ def compose_down(name, worker_api, mapped_ports=SERVICE_PORTS, :param name: The name of the cluster :param mapped_ports: The mapped ports list :param worker_api: Docker host daemon - :param network_type: Fabric image version - :param consensus_plugin: Cluster consensus type - :param consensus_mode: Cluster consensus mode :param log_type: which log plugin for host :param log_server: syslog server - :param cluster_size: the size of the cluster + :param log_level: level of the logging + :param config: network config :param timeout: Docker client timeout :return: """ - logger.debug("Compose remove {} with worker_api={}, network_type={} " - "config={}".format(name, worker_api, network_type, - config.get_data())) + logger.debug("Compose remove {} with worker_api={}, config={}".format( + name, worker_api, config.get_data())) - _compose_set_env(name, worker_api, mapped_ports, network_type, - log_level, log_type, log_server, config) + _compose_set_env(name, worker_api, mapped_ports, log_level, log_type, + log_server, config) # project = get_project(COMPOSE_FILE_PATH+"/"+consensus_plugin) - project_path = COMPOSE_FILE_PATH + "/{}/".format(network_type) + log_type - logger.debug("project_path = {}".format(project_path)) logger.debug(os.environ) - project = get_project(project_path) + project = get_project(COMPOSE_FILE_PATH + os.sep + config['network_type'] + + os.sep + log_type) # project.down(remove_orphans=True) project.stop(timeout=timeout) diff --git a/src/common/__init__.py b/src/common/__init__.py index 4a39ea47..3bced7d7 100644 --- a/src/common/__init__.py +++ b/src/common/__init__.py @@ -12,8 +12,9 @@ from .utils import \ PEER_SERVICE_PORTS, CA_SERVICE_PORTS, SERVICE_PORTS, \ NETWORK_TYPES, NETWORK_TYPE_FABRIC_V1, NETWORK_TYPE_FABRIC_PRE_V1, \ - CONSENSUS_PLUGINS_FABRIC_V1, CONSENSUS_MODES, CONSENSUS_TYPES, \ - WORKER_TYPES, \ + CONSENSUS_PLUGINS_FABRIC_V1, CONSENSUS_PLUGIN_SOLO,\ + CONSENSUS_MODES, CONSENSUS_TYPES_FABRIC_V1, \ + WORKER_TYPES, WORKER_TYPE_DOCKER, WORKER_TYPE_SWARM, WORKER_TYPE_K8S, \ CLUSTER_PORT_START, CLUSTER_PORT_STEP, \ NETWORK_SIZE_FABRIC_PRE_V1, NETWORK_SIZE_FABRIC_V1, \ CLUSTER_NETWORK, \ diff --git a/src/common/fabric_network_config.py b/src/common/fabric_network_config.py index cf2a15b2..27e395ff 100644 --- a/src/common/fabric_network_config.py +++ b/src/common/fabric_network_config.py @@ -7,8 +7,8 @@ from common.blockchain_network_config import BlockchainNetworkConfig from common import CONSENSUS_PLUGINS_FABRIC_V1, CONSENSUS_MODES, \ - NETWORK_SIZE_FABRIC_PRE_V1, \ - NETWORK_SIZE_FABRIC_V1, \ + NETWORK_TYPE_FABRIC_PRE_V1, NETWORK_TYPE_FABRIC_V1, \ + NETWORK_SIZE_FABRIC_PRE_V1, NETWORK_SIZE_FABRIC_V1, \ log_handler, LOG_LEVEL logger = logging.getLogger(__name__) @@ -33,6 +33,7 @@ def __init__(self, consensus_plugin, consensus_mode, size): >>> config = FabricPreNetworkConfig('plugin', 'mode', 'size') """ + self.network_type = NETWORK_TYPE_FABRIC_PRE_V1 self.consensus_plugin = consensus_plugin self.consensus_mode = consensus_mode self.size = size @@ -76,6 +77,7 @@ def __init__(self, consensus_plugin, size): consensus_plugin: plugin of consensus, e.g., solo, kafka size: number of containers in the network """ + self.network_type = NETWORK_TYPE_FABRIC_V1 self.consensus_plugin = consensus_plugin self.size = size super(FabricV1NetworkConfig, self).__init__() diff --git a/src/common/utils.py b/src/common/utils.py index fdf8b73c..f9fb9eab 100644 --- a/src/common/utils.py +++ b/src/common/utils.py @@ -56,12 +56,12 @@ CONSENSUS_MODE_BATCH = 'batch' CONSENSUS_MODES = [CONSENSUS_MODE_BATCH] # pbft has various modes -CONSENSUS_TYPES_PRE_V1 = [ +CONSENSUS_TYPES_FABRIC_PRE_V1 = [ (CONSENSUS_PLUGIN_NOOPS, ''), (CONSENSUS_PLUGIN_PBFT, CONSENSUS_MODE_BATCH), ] -CONSENSUS_TYPES = [ +CONSENSUS_TYPES_FABRIC_V1 = [ (CONSENSUS_PLUGIN_SOLO, ''), (CONSENSUS_PLUGIN_KAFKA, '') ] diff --git a/src/modules/cluster.py b/src/modules/cluster.py index eea67e1e..eec848b3 100644 --- a/src/modules/cluster.py +++ b/src/modules/cluster.py @@ -21,7 +21,8 @@ from common import db, log_handler, LOG_LEVEL from common import CLUSTER_PORT_START, CLUSTER_PORT_STEP, \ NETWORK_TYPE_FABRIC_PRE_V1, NETWORK_TYPE_FABRIC_V1, \ - CONSENSUS_PLUGINS_FABRIC_V1, CONSENSUS_MODES, WORKER_TYPES, \ + CONSENSUS_PLUGINS_FABRIC_V1, CONSENSUS_MODES, \ + WORKER_TYPES, WORKER_TYPE_DOCKER, WORKER_TYPE_SWARM, WORKER_TYPE_K8S, \ SYS_CREATOR, SYS_DELETER, SYS_USER, SYS_RESETTING, \ NETWORK_SIZE_FABRIC_PRE_V1, \ PEER_SERVICE_PORTS, CA_SERVICE_PORTS @@ -89,7 +90,7 @@ def get_by_id(self, id, col_name="active"): return {} return self._serialize(cluster) - def create(self, name, host_id, network_type, config, start_port=0, + def create(self, name, host_id, config, start_port=0, user_id=""): """ Create a cluster based on given data @@ -98,7 +99,6 @@ def create(self, name, host_id, network_type, config, start_port=0, name: name of the cluster host_id: id of the host URL - network_type: type of the network config: network configuration start_port: first service port for cluster, will generate if not given @@ -106,8 +106,9 @@ def create(self, name, host_id, network_type, config, start_port=0, return: Id of the created cluster or None """ - logger.info("Create cluster {}, host_id={}, config={}" - .format(name, host_id, network_type, config.get_data())) + logger.info("Create cluster {}, host_id={}, config={}, start_port={}, " + "user_id={}".format(name, host_id, config.get_data(), + start_port, user_id)) worker = self.host_handler.get_active_host_by_id(host_id) if not worker: @@ -135,7 +136,9 @@ def create(self, name, host_id, network_type, config, start_port=0, mapped_ports.update(peer_mapped_ports) mapped_ports.update(ca_mapped_ports) + logger.debug("mapped_ports={}".format(mapped_ports)) + network_type = config['network_type'] net = { # net is a blockchain network instance 'id': '', 'name': name, @@ -181,16 +184,23 @@ def create(self, name, host_id, network_type, config, start_port=0, # start compose project, failed then clean and return logger.debug("Start compose project with name={}".format(cid)) containers = self.cluster_agents[worker.get('type')]\ - .create(cid, mapped_ports, worker, user_id=user_id, - network_type=network_type, config=config) + .create(cid, mapped_ports, worker, config=config, user_id=user_id) if not containers: logger.warning("failed to start cluster={}, then delete" .format(name)) self.delete(id=cid, record=False, forced=True) return None - peer_host_ip = self._get_service_ip(cid, 'vp0') - ca_host_ip = self._get_service_ip(cid, 'membersrvc') + access_peer, access_ca = '', '' + if network_type == NETWORK_TYPE_FABRIC_V1: # fabric v1.0 + access_peer = 'peer0.org1.example.com' + access_ca = 'ca.example.com' + elif network_type == NETWORK_TYPE_FABRIC_PRE_V1: # fabric v0.6 + access_peer = 'vp0' + access_ca = 'membersrvc' + + peer_host_ip = self._get_service_ip(cid, access_peer) + ca_host_ip = self._get_service_ip(cid, access_ca) # no api_url, then clean and return if not peer_host_ip: # not valid api_url logger.error("Error to find peer host url, cleanup") @@ -279,8 +289,8 @@ def delete(self, id, record=False, forced=False): else: return False - if not self.cluster_agents[h.get('type')]\ - .delete(id, worker_api, network_type, config): + if not self.cluster_agents[h.get('type')].delete(id, worker_api, + config): logger.warning("Error to run compose clean work") self.col_active.update_one({"id": id}, {"$set": {"user_id": user_id}}) @@ -413,7 +423,6 @@ def start(self, cluster_id): result = self.cluster_agents[h.get('type')].start( name=cluster_id, worker_api=h.get('worker_api'), mapped_ports=c.get('mapped_ports', PEER_SERVICE_PORTS), - network_type=c.get('network_type'), log_type=h.get('log_type'), log_level=h.get('log_level'), log_server='', @@ -458,7 +467,6 @@ def restart(self, cluster_id): result = self.cluster_agents[h.get('type')].restart( name=cluster_id, worker_api=h.get('worker_api'), mapped_ports=c.get('mapped_ports', PEER_SERVICE_PORTS), - network_type=c.get('network_type'), log_type=h.get('log_type'), log_level=h.get('log_level'), log_server='', @@ -501,7 +509,6 @@ def stop(self, cluster_id): result = self.cluster_agents[h.get('type')].stop( name=cluster_id, worker_api=h.get('worker_api'), mapped_ports=c.get('mapped_ports', PEER_SERVICE_PORTS), - network_type=c.get('network_type'), log_type=h.get('log_type'), log_level=h.get('log_level'), log_server='', @@ -546,8 +553,7 @@ def reset(self, cluster_id, record=False): else: return False if not self.create(name=cluster_name, host_id=host_id, - start_port=mapped_ports['rest'], - network_type=network_type, config=config): + start_port=mapped_ports['rest'], config=config): logger.warning("Fail to recreate cluster {}".format(cluster_name)) return False return True @@ -605,14 +611,14 @@ def _get_service_ip(self, cluster_id, node='vp0'): logger.warning("Found invalid host_type=%s".format(host_type)) return "" # we should diff with simple host and swarm host here - if host_type == WORKER_TYPES[0]: # single + if host_type == WORKER_TYPE_DOCKER: # single segs = worker_api.split(":") # tcp://x.x.x.x:2375 if len(segs) != 3: logger.error("Invalid daemon url = ", worker_api) return "" host_ip = segs[1][2:] logger.debug("single host, ip = {}".format(host_ip)) - elif host_type == WORKER_TYPES[1]: # swarm + elif host_type == WORKER_TYPE_SWARM: # swarm host_ip = get_swarm_node_ip(worker_api, "{}_{}".format( cluster_id, node)) logger.debug("swarm host, ip = {}".format(host_ip)) @@ -666,36 +672,41 @@ def refresh_health(self, cluster_id, timeout=5): :param timeout: how many seconds to wait for receiving response :return: True or False """ - logger.debug("checking health of cluster id={}".format(cluster_id)) cluster = self.get_by_id(cluster_id) + logger.debug("checking health of cluster={}".format(cluster)) if not cluster: logger.warning("Cannot found cluster id={}".format(cluster_id)) return True if cluster.get('status') != 'running': logger.warning("cluster is not running id={}".format(cluster_id)) return True - rest_api = cluster["service_url"]['rest'] + "/network/peers" - if not rest_api.startswith('http'): - rest_api = 'http://' + rest_api - try: - r = requests.get(rest_api, timeout=timeout) - except Exception as e: - logger.error("Error to refresh health of cluster {}: {}".format( - cluster_id, e)) - return True - - peers = r.json().get("peers") - - if len(peers) == cluster["size"]: - self.db_update_one({"id": cluster_id}, - {"$set": {"health": "OK"}}) + if cluster.get('network_type') == NETWORK_TYPE_FABRIC_PRE_V1: + rest_api = cluster["service_url"]['rest'] + "/network/peers" + if not rest_api.startswith('http'): + rest_api = 'http://' + rest_api + try: + r = requests.get(rest_api, timeout=timeout) + except Exception as e: + logger.error("Error to refresh health of cluster {}: {}". + format(cluster_id, e)) + return True + + peers = r.json().get("peers") + + if len(peers) == cluster["size"]: + self.db_update_one({"id": cluster_id}, + {"$set": {"health": "OK"}}) + return True + else: + logger.debug("checking result of cluster id={}".format( + cluster_id, peers)) + self.db_update_one({"id": cluster_id}, + {"$set": {"health": "FAIL"}}) + return False + elif cluster.get('network_type') == NETWORK_TYPE_FABRIC_V1: + # TODO: check fabric 1.0 network health status return True - else: - logger.debug("checking result of cluster id={}".format( - cluster_id, peers)) - self.db_update_one({"id": cluster_id}, - {"$set": {"health": "FAIL"}}) - return False + return True def db_update_one(self, filter, operations, after=True, col="active"): """ diff --git a/src/modules/host.py b/src/modules/host.py index 82ec1c15..8cd0e420 100644 --- a/src/modules/host.py +++ b/src/modules/host.py @@ -16,9 +16,13 @@ sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..')) from common import \ db, log_handler, \ + FabricV1NetworkConfig, \ LOG_LEVEL, CLUSTER_LOG_TYPES, CLUSTER_LOG_LEVEL, \ - NETWORK_SIZE_FABRIC_PRE_V1, CLUSTER_PORT_START, CLUSTER_PORT_STEP, \ - CONSENSUS_TYPES, WORKER_TYPES + NETWORK_TYPE_FABRIC_V1, \ + NETWORK_SIZE_FABRIC_V1, \ + CLUSTER_PORT_START, CLUSTER_PORT_STEP, \ + CONSENSUS_PLUGINS_FABRIC_V1, CONSENSUS_PLUGIN_SOLO, \ + WORKER_TYPES from agent import DockerHost, KubernetesHost @@ -217,12 +221,14 @@ def create_cluster_work(start_port): cluster_name = "{}_{}".format( host.get("name"), int((start_port - CLUSTER_PORT_START) / CLUSTER_PORT_STEP)) - consensus_plugin, consensus_mode = random.choice(CONSENSUS_TYPES) - cluster_size = random.choice(NETWORK_SIZE_FABRIC_PRE_V1) - cid = cluster.cluster_handler.create( - name=cluster_name, host_id=id, start_port=start_port, + consensus_plugin = CONSENSUS_PLUGIN_SOLO + cluster_size = random.choice(NETWORK_SIZE_FABRIC_V1) + config = FabricV1NetworkConfig( consensus_plugin=consensus_plugin, - consensus_mode=consensus_mode, size=cluster_size) + size=cluster_size) + cid = cluster.cluster_handler.create(name=cluster_name, + host_id=id, config=config, + start_port=start_port) if cid: logger.debug("Create cluster {} with id={}".format( cluster_name, cid)) diff --git a/src/themes/basic/static/css/jquery.dataTables.min.css b/src/themes/basic/static/css/jquery.dataTables.min.css index 781de6bf..db9f0476 100644 --- a/src/themes/basic/static/css/jquery.dataTables.min.css +++ b/src/themes/basic/static/css/jquery.dataTables.min.css @@ -1 +1 @@ -table.dataTable{width:100%;margin:0 auto;clear:both;border-collapse:separate;border-spacing:0}table.dataTable thead th,table.dataTable tfoot th{font-weight:bold}table.dataTable thead th,table.dataTable thead td{padding:10px 18px;border-bottom:1px solid #111}table.dataTable thead th:active,table.dataTable thead td:active{outline:none}table.dataTable tfoot th,table.dataTable tfoot td{padding:10px 18px 6px 18px;border-top:1px solid #111}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc{cursor:pointer;*cursor:hand}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{background-repeat:no-repeat;background-position:center right}table.dataTable thead .sorting{background-image:url("../images/sort_both.png")}table.dataTable thead .sorting_asc{background-image:url("../images/sort_asc.png")}table.dataTable thead .sorting_desc{background-image:url("../images/sort_desc.png")}table.dataTable thead .sorting_asc_disabled{background-image:url("../images/sort_asc_disabled.png")}table.dataTable thead .sorting_desc_disabled{background-image:url("../images/sort_desc_disabled.png")}table.dataTable tbody tr{background-color:#ffffff}table.dataTable tbody tr.selected{background-color:#B0BED9}table.dataTable tbody th,table.dataTable tbody td{padding:8px 10px}table.dataTable.row-border tbody th,table.dataTable.row-border tbody td,table.dataTable.display tbody th,table.dataTable.display tbody td{border-top:1px solid #ddd}table.dataTable.row-border tbody tr:first-child th,table.dataTable.row-border tbody tr:first-child td,table.dataTable.display tbody tr:first-child th,table.dataTable.display tbody tr:first-child td{border-top:none}table.dataTable.cell-border tbody th,table.dataTable.cell-border tbody td{border-top:1px solid #ddd;border-right:1px solid #ddd}table.dataTable.cell-border tbody tr th:first-child,table.dataTable.cell-border tbody tr td:first-child{border-left:1px solid #ddd}table.dataTable.cell-border tbody tr:first-child th,table.dataTable.cell-border tbody tr:first-child td{border-top:none}table.dataTable.stripe tbody tr.odd,table.dataTable.display tbody tr.odd{background-color:#f9f9f9}table.dataTable.stripe tbody tr.odd.selected,table.dataTable.display tbody tr.odd.selected{background-color:#acbad4}table.dataTable.hover tbody tr:hover,table.dataTable.display tbody tr:hover{background-color:#f6f6f6}table.dataTable.hover tbody tr:hover.selected,table.dataTable.display tbody tr:hover.selected{background-color:#aab7d1}table.dataTable.order-column tbody tr>.sorting_1,table.dataTable.order-column tbody tr>.sorting_2,table.dataTable.order-column tbody tr>.sorting_3,table.dataTable.display tbody tr>.sorting_1,table.dataTable.display tbody tr>.sorting_2,table.dataTable.display tbody tr>.sorting_3{background-color:#fafafa}table.dataTable.order-column tbody tr.selected>.sorting_1,table.dataTable.order-column tbody tr.selected>.sorting_2,table.dataTable.order-column tbody tr.selected>.sorting_3,table.dataTable.display tbody tr.selected>.sorting_1,table.dataTable.display tbody tr.selected>.sorting_2,table.dataTable.display tbody tr.selected>.sorting_3{background-color:#acbad5}table.dataTable.display tbody tr.odd>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd>.sorting_1{background-color:#f1f1f1}table.dataTable.display tbody tr.odd>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd>.sorting_2{background-color:#f3f3f3}table.dataTable.display tbody tr.odd>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd>.sorting_3{background-color:whitesmoke}table.dataTable.display tbody tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_1{background-color:#a6b4cd}table.dataTable.display tbody tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_2{background-color:#a8b5cf}table.dataTable.display tbody tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_3{background-color:#a9b7d1}table.dataTable.display tbody tr.even>.sorting_1,table.dataTable.order-column.stripe tbody tr.even>.sorting_1{background-color:#fafafa}table.dataTable.display tbody tr.even>.sorting_2,table.dataTable.order-column.stripe tbody tr.even>.sorting_2{background-color:#fcfcfc}table.dataTable.display tbody tr.even>.sorting_3,table.dataTable.order-column.stripe tbody tr.even>.sorting_3{background-color:#fefefe}table.dataTable.display tbody tr.even.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_1{background-color:#acbad5}table.dataTable.display tbody tr.even.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_2{background-color:#aebcd6}table.dataTable.display tbody tr.even.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_3{background-color:#afbdd8}table.dataTable.display tbody tr:hover>.sorting_1,table.dataTable.order-column.hover tbody tr:hover>.sorting_1{background-color:#eaeaea}table.dataTable.display tbody tr:hover>.sorting_2,table.dataTable.order-column.hover tbody tr:hover>.sorting_2{background-color:#ececec}table.dataTable.display tbody tr:hover>.sorting_3,table.dataTable.order-column.hover tbody tr:hover>.sorting_3{background-color:#efefef}table.dataTable.display tbody tr:hover.selected>.sorting_1,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_1{background-color:#a2aec7}table.dataTable.display tbody tr:hover.selected>.sorting_2,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_2{background-color:#a3b0c9}table.dataTable.display tbody tr:hover.selected>.sorting_3,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_3{background-color:#a5b2cb}table.dataTable.no-footer{border-bottom:1px solid #111}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}table.dataTable.compact thead th,table.dataTable.compact thead td{padding:4px 17px 4px 4px}table.dataTable.compact tfoot th,table.dataTable.compact tfoot td{padding:4px}table.dataTable.compact tbody th,table.dataTable.compact tbody td{padding:4px}table.dataTable th.dt-left,table.dataTable td.dt-left{text-align:left}table.dataTable th.dt-center,table.dataTable td.dt-center,table.dataTable td.dataTables_empty{text-align:center}table.dataTable th.dt-right,table.dataTable td.dt-right{text-align:right}table.dataTable th.dt-justify,table.dataTable td.dt-justify{text-align:justify}table.dataTable th.dt-nowrap,table.dataTable td.dt-nowrap{white-space:nowrap}table.dataTable thead th.dt-head-left,table.dataTable thead td.dt-head-left,table.dataTable tfoot th.dt-head-left,table.dataTable tfoot td.dt-head-left{text-align:left}table.dataTable thead th.dt-head-center,table.dataTable thead td.dt-head-center,table.dataTable tfoot th.dt-head-center,table.dataTable tfoot td.dt-head-center{text-align:center}table.dataTable thead th.dt-head-right,table.dataTable thead td.dt-head-right,table.dataTable tfoot th.dt-head-right,table.dataTable tfoot td.dt-head-right{text-align:right}table.dataTable thead th.dt-head-justify,table.dataTable thead td.dt-head-justify,table.dataTable tfoot th.dt-head-justify,table.dataTable tfoot td.dt-head-justify{text-align:justify}table.dataTable thead th.dt-head-nowrap,table.dataTable thead td.dt-head-nowrap,table.dataTable tfoot th.dt-head-nowrap,table.dataTable tfoot td.dt-head-nowrap{white-space:nowrap}table.dataTable tbody th.dt-body-left,table.dataTable tbody td.dt-body-left{text-align:left}table.dataTable tbody th.dt-body-center,table.dataTable tbody td.dt-body-center{text-align:center}table.dataTable tbody th.dt-body-right,table.dataTable tbody td.dt-body-right{text-align:right}table.dataTable tbody th.dt-body-justify,table.dataTable tbody td.dt-body-justify{text-align:justify}table.dataTable tbody th.dt-body-nowrap,table.dataTable tbody td.dt-body-nowrap{white-space:nowrap}table.dataTable,table.dataTable th,table.dataTable td{-webkit-box-sizing:content-box;box-sizing:content-box}.dataTables_wrapper{position:relative;clear:both;*zoom:1;zoom:1}.dataTables_wrapper .dataTables_length{float:left}.dataTables_wrapper .dataTables_filter{float:right;text-align:right}.dataTables_wrapper .dataTables_filter input{margin-left:0.5em}.dataTables_wrapper .dataTables_info{clear:both;float:left;padding-top:0.755em}.dataTables_wrapper .dataTables_paginate{float:right;text-align:right;padding-top:0.25em}.dataTables_wrapper .dataTables_paginate .paginate_button{box-sizing:border-box;display:inline-block;min-width:1.5em;padding:0.5em 1em;margin-left:2px;text-align:center;text-decoration:none !important;cursor:pointer;*cursor:hand;color:#333 !important;border:1px solid transparent;border-radius:2px}.dataTables_wrapper .dataTables_paginate .paginate_button.current,.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{color:#333 !important;border:1px solid #979797;background-color:white;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #fff), color-stop(100%, #dcdcdc));background:-webkit-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-moz-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-ms-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-o-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:linear-gradient(to bottom, #fff 0%, #dcdcdc 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{cursor:default;color:#666 !important;border:1px solid transparent;background:transparent;box-shadow:none}.dataTables_wrapper .dataTables_paginate .paginate_button:hover{color:white !important;border:1px solid #111;background-color:#585858;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));background:-webkit-linear-gradient(top, #585858 0%, #111 100%);background:-moz-linear-gradient(top, #585858 0%, #111 100%);background:-ms-linear-gradient(top, #585858 0%, #111 100%);background:-o-linear-gradient(top, #585858 0%, #111 100%);background:linear-gradient(to bottom, #585858 0%, #111 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button:active{outline:none;background-color:#2b2b2b;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));background:-webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);box-shadow:inset 0 0 3px #111}.dataTables_wrapper .dataTables_paginate .ellipsis{padding:0 1em}.dataTables_wrapper .dataTables_processing{position:absolute;top:50%;left:50%;width:100%;height:40px;margin-left:-50%;margin-top:-25px;padding-top:20px;text-align:center;font-size:1.2em;background-color:white;background:-webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255,255,255,0)), color-stop(25%, rgba(255,255,255,0.9)), color-stop(75%, rgba(255,255,255,0.9)), color-stop(100%, rgba(255,255,255,0)));background:-webkit-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-moz-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-ms-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-o-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:linear-gradient(to right, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%)}.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter,.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_processing,.dataTables_wrapper .dataTables_paginate{color:#333}.dataTables_wrapper .dataTables_scroll{clear:both}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody{*margin-top:-1px;-webkit-overflow-scrolling:touch}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td{vertical-align:middle}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td>div.dataTables_sizing{height:0;overflow:hidden;margin:0 !important;padding:0 !important}.dataTables_wrapper.no-footer .dataTables_scrollBody{border-bottom:1px solid #111}.dataTables_wrapper.no-footer div.dataTables_scrollHead table,.dataTables_wrapper.no-footer div.dataTables_scrollBody table{border-bottom:none}.dataTables_wrapper:after{visibility:hidden;display:block;content:"";clear:both;height:0}@media screen and (max-width: 767px){.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_paginate{float:none;text-align:center}.dataTables_wrapper .dataTables_paginate{margin-top:0.5em}}@media screen and (max-width: 640px){.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter{float:none;text-align:center}.dataTables_wrapper .dataTables_filter{margin-top:0.5em}} +table.dataTable{width:100%;margin:0 auto;clear:both;border-collapse:separate;border-spacing:0}table.dataTable thead th,table.dataTable tfoot th{font-weight:bold}table.dataTable thead th,table.dataTable thead td{padding:10px 18px;border-bottom:1px solid #111}table.dataTable thead th:active,table.dataTable thead td:active{outline:none}table.dataTable tfoot th,table.dataTable tfoot td{padding:10px 18px 6px 18px;border-top:1px solid #111}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc{cursor:pointer;*cursor:hand}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{background-repeat:no-repeat;background-position:center right}table.dataTable thead .sorting{background-image:url("../img/sort_both.png")}table.dataTable thead .sorting_asc{background-image:url("../img/sort_asc.png")}table.dataTable thead .sorting_desc{background-image:url("../img/sort_desc.png")}table.dataTable thead .sorting_asc_disabled{background-image:url("../img/sort_asc_disabled.png")}table.dataTable thead .sorting_desc_disabled{background-image:url("../img/sort_desc_disabled.png")}table.dataTable tbody tr{background-color:#ffffff}table.dataTable tbody tr.selected{background-color:#B0BED9}table.dataTable tbody th,table.dataTable tbody td{padding:8px 10px}table.dataTable.row-border tbody th,table.dataTable.row-border tbody td,table.dataTable.display tbody th,table.dataTable.display tbody td{border-top:1px solid #ddd}table.dataTable.row-border tbody tr:first-child th,table.dataTable.row-border tbody tr:first-child td,table.dataTable.display tbody tr:first-child th,table.dataTable.display tbody tr:first-child td{border-top:none}table.dataTable.cell-border tbody th,table.dataTable.cell-border tbody td{border-top:1px solid #ddd;border-right:1px solid #ddd}table.dataTable.cell-border tbody tr th:first-child,table.dataTable.cell-border tbody tr td:first-child{border-left:1px solid #ddd}table.dataTable.cell-border tbody tr:first-child th,table.dataTable.cell-border tbody tr:first-child td{border-top:none}table.dataTable.stripe tbody tr.odd,table.dataTable.display tbody tr.odd{background-color:#f9f9f9}table.dataTable.stripe tbody tr.odd.selected,table.dataTable.display tbody tr.odd.selected{background-color:#acbad4}table.dataTable.hover tbody tr:hover,table.dataTable.display tbody tr:hover{background-color:#f6f6f6}table.dataTable.hover tbody tr:hover.selected,table.dataTable.display tbody tr:hover.selected{background-color:#aab7d1}table.dataTable.order-column tbody tr>.sorting_1,table.dataTable.order-column tbody tr>.sorting_2,table.dataTable.order-column tbody tr>.sorting_3,table.dataTable.display tbody tr>.sorting_1,table.dataTable.display tbody tr>.sorting_2,table.dataTable.display tbody tr>.sorting_3{background-color:#fafafa}table.dataTable.order-column tbody tr.selected>.sorting_1,table.dataTable.order-column tbody tr.selected>.sorting_2,table.dataTable.order-column tbody tr.selected>.sorting_3,table.dataTable.display tbody tr.selected>.sorting_1,table.dataTable.display tbody tr.selected>.sorting_2,table.dataTable.display tbody tr.selected>.sorting_3{background-color:#acbad5}table.dataTable.display tbody tr.odd>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd>.sorting_1{background-color:#f1f1f1}table.dataTable.display tbody tr.odd>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd>.sorting_2{background-color:#f3f3f3}table.dataTable.display tbody tr.odd>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd>.sorting_3{background-color:whitesmoke}table.dataTable.display tbody tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_1{background-color:#a6b4cd}table.dataTable.display tbody tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_2{background-color:#a8b5cf}table.dataTable.display tbody tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_3{background-color:#a9b7d1}table.dataTable.display tbody tr.even>.sorting_1,table.dataTable.order-column.stripe tbody tr.even>.sorting_1{background-color:#fafafa}table.dataTable.display tbody tr.even>.sorting_2,table.dataTable.order-column.stripe tbody tr.even>.sorting_2{background-color:#fcfcfc}table.dataTable.display tbody tr.even>.sorting_3,table.dataTable.order-column.stripe tbody tr.even>.sorting_3{background-color:#fefefe}table.dataTable.display tbody tr.even.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_1{background-color:#acbad5}table.dataTable.display tbody tr.even.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_2{background-color:#aebcd6}table.dataTable.display tbody tr.even.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_3{background-color:#afbdd8}table.dataTable.display tbody tr:hover>.sorting_1,table.dataTable.order-column.hover tbody tr:hover>.sorting_1{background-color:#eaeaea}table.dataTable.display tbody tr:hover>.sorting_2,table.dataTable.order-column.hover tbody tr:hover>.sorting_2{background-color:#ececec}table.dataTable.display tbody tr:hover>.sorting_3,table.dataTable.order-column.hover tbody tr:hover>.sorting_3{background-color:#efefef}table.dataTable.display tbody tr:hover.selected>.sorting_1,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_1{background-color:#a2aec7}table.dataTable.display tbody tr:hover.selected>.sorting_2,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_2{background-color:#a3b0c9}table.dataTable.display tbody tr:hover.selected>.sorting_3,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_3{background-color:#a5b2cb}table.dataTable.no-footer{border-bottom:1px solid #111}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}table.dataTable.compact thead th,table.dataTable.compact thead td{padding:4px 17px 4px 4px}table.dataTable.compact tfoot th,table.dataTable.compact tfoot td{padding:4px}table.dataTable.compact tbody th,table.dataTable.compact tbody td{padding:4px}table.dataTable th.dt-left,table.dataTable td.dt-left{text-align:left}table.dataTable th.dt-center,table.dataTable td.dt-center,table.dataTable td.dataTables_empty{text-align:center}table.dataTable th.dt-right,table.dataTable td.dt-right{text-align:right}table.dataTable th.dt-justify,table.dataTable td.dt-justify{text-align:justify}table.dataTable th.dt-nowrap,table.dataTable td.dt-nowrap{white-space:nowrap}table.dataTable thead th.dt-head-left,table.dataTable thead td.dt-head-left,table.dataTable tfoot th.dt-head-left,table.dataTable tfoot td.dt-head-left{text-align:left}table.dataTable thead th.dt-head-center,table.dataTable thead td.dt-head-center,table.dataTable tfoot th.dt-head-center,table.dataTable tfoot td.dt-head-center{text-align:center}table.dataTable thead th.dt-head-right,table.dataTable thead td.dt-head-right,table.dataTable tfoot th.dt-head-right,table.dataTable tfoot td.dt-head-right{text-align:right}table.dataTable thead th.dt-head-justify,table.dataTable thead td.dt-head-justify,table.dataTable tfoot th.dt-head-justify,table.dataTable tfoot td.dt-head-justify{text-align:justify}table.dataTable thead th.dt-head-nowrap,table.dataTable thead td.dt-head-nowrap,table.dataTable tfoot th.dt-head-nowrap,table.dataTable tfoot td.dt-head-nowrap{white-space:nowrap}table.dataTable tbody th.dt-body-left,table.dataTable tbody td.dt-body-left{text-align:left}table.dataTable tbody th.dt-body-center,table.dataTable tbody td.dt-body-center{text-align:center}table.dataTable tbody th.dt-body-right,table.dataTable tbody td.dt-body-right{text-align:right}table.dataTable tbody th.dt-body-justify,table.dataTable tbody td.dt-body-justify{text-align:justify}table.dataTable tbody th.dt-body-nowrap,table.dataTable tbody td.dt-body-nowrap{white-space:nowrap}table.dataTable,table.dataTable th,table.dataTable td{-webkit-box-sizing:content-box;box-sizing:content-box}.dataTables_wrapper{position:relative;clear:both;*zoom:1;zoom:1}.dataTables_wrapper .dataTables_length{float:left}.dataTables_wrapper .dataTables_filter{float:right;text-align:right}.dataTables_wrapper .dataTables_filter input{margin-left:0.5em}.dataTables_wrapper .dataTables_info{clear:both;float:left;padding-top:0.755em}.dataTables_wrapper .dataTables_paginate{float:right;text-align:right;padding-top:0.25em}.dataTables_wrapper .dataTables_paginate .paginate_button{box-sizing:border-box;display:inline-block;min-width:1.5em;padding:0.5em 1em;margin-left:2px;text-align:center;text-decoration:none !important;cursor:pointer;*cursor:hand;color:#333 !important;border:1px solid transparent;border-radius:2px}.dataTables_wrapper .dataTables_paginate .paginate_button.current,.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{color:#333 !important;border:1px solid #979797;background-color:white;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #fff), color-stop(100%, #dcdcdc));background:-webkit-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-moz-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-ms-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-o-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:linear-gradient(to bottom, #fff 0%, #dcdcdc 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{cursor:default;color:#666 !important;border:1px solid transparent;background:transparent;box-shadow:none}.dataTables_wrapper .dataTables_paginate .paginate_button:hover{color:white !important;border:1px solid #111;background-color:#585858;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));background:-webkit-linear-gradient(top, #585858 0%, #111 100%);background:-moz-linear-gradient(top, #585858 0%, #111 100%);background:-ms-linear-gradient(top, #585858 0%, #111 100%);background:-o-linear-gradient(top, #585858 0%, #111 100%);background:linear-gradient(to bottom, #585858 0%, #111 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button:active{outline:none;background-color:#2b2b2b;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));background:-webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);box-shadow:inset 0 0 3px #111}.dataTables_wrapper .dataTables_paginate .ellipsis{padding:0 1em}.dataTables_wrapper .dataTables_processing{position:absolute;top:50%;left:50%;width:100%;height:40px;margin-left:-50%;margin-top:-25px;padding-top:20px;text-align:center;font-size:1.2em;background-color:white;background:-webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255,255,255,0)), color-stop(25%, rgba(255,255,255,0.9)), color-stop(75%, rgba(255,255,255,0.9)), color-stop(100%, rgba(255,255,255,0)));background:-webkit-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-moz-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-ms-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-o-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:linear-gradient(to right, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%)}.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter,.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_processing,.dataTables_wrapper .dataTables_paginate{color:#333}.dataTables_wrapper .dataTables_scroll{clear:both}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody{*margin-top:-1px;-webkit-overflow-scrolling:touch}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td{vertical-align:middle}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td>div.dataTables_sizing{height:0;overflow:hidden;margin:0 !important;padding:0 !important}.dataTables_wrapper.no-footer .dataTables_scrollBody{border-bottom:1px solid #111}.dataTables_wrapper.no-footer div.dataTables_scrollHead table,.dataTables_wrapper.no-footer div.dataTables_scrollBody table{border-bottom:none}.dataTables_wrapper:after{visibility:hidden;display:block;content:"";clear:both;height:0}@media screen and (max-width: 767px){.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_paginate{float:none;text-align:center}.dataTables_wrapper .dataTables_paginate{margin-top:0.5em}}@media screen and (max-width: 640px){.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter{float:none;text-align:center}.dataTables_wrapper .dataTables_filter{margin-top:0.5em}} diff --git a/src/themes/basic/templates/cluster_info.html b/src/themes/basic/templates/cluster_info.html index aab88af5..4d072ded 100644 --- a/src/themes/basic/templates/cluster_info.html +++ b/src/themes/basic/templates/cluster_info.html @@ -21,14 +21,15 @@

Chain Information

{% endif %}
Host
{{item .host_id}}
-
User Id
{{item.user_id}}
Create Time
{{item.create_ts}}
-
Apply Time
{{item.apply_ts}}
-
Release Time
{{item.release_ts}}
-
Duration
{{item.duration}}
+
Network Type
{{item.network_type}}
Size
{{item.size|string}}
Status
{{item.status}}
Health
{{item.health}}
+
User Id
{{item.user_id}}
+
Apply Time
{{item.apply_ts}}
+
Release Time
{{item.release_ts}}
+
Duration
{{item.duration}}
Service URL
{% for k in item.service_url%} {{ k }}: {{item.service_url[k]}}