distributed-deploy: add distributed deploy tools for prod env

Signed-off-by: zeoio <kinsleer@outlook.com>
This commit is contained in:
zeoio 2020-04-23 14:33:00 +08:00
parent 1343ccb628
commit 958749e76c
313 changed files with 16183 additions and 0 deletions

View file

@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8

View file

@ -0,0 +1,4 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

View file

@ -0,0 +1,3 @@
# 分布式部署
该项目主要实现fabric一键分布式部署。fabric官网的例子只能实现单节点部署链网络包括ordererpeer和couchdb和chaincode节点如果要实现在多个节点部署链网络需要手动修改配置文件和执行相关命令此过程比较麻烦且容易出错。本部署包主要是为解决此问题而创立方便生产环境下运维人员快速实现分布式部署fabric链网络。

View file

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="target/generated-sources/annotations">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View file

@ -0,0 +1,102 @@
<factorypath>
<factorypathentry kind="VARJAR" id="M2_REPO/commons-io/commons-io/1.3.2/commons-io-1.3.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/commons/commons-compress/1.18/commons-compress-1.18.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-web/2.0.6.RELEASE/spring-boot-starter-web-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter/2.0.6.RELEASE/spring-boot-starter-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot/2.0.6.RELEASE/spring-boot-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-autoconfigure/2.0.6.RELEASE/spring-boot-autoconfigure-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-logging/2.0.6.RELEASE/spring-boot-starter-logging-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/logging/log4j/log4j-to-slf4j/2.10.0/log4j-to-slf4j-2.10.0.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/logging/log4j/log4j-api/2.10.0/log4j-api-2.10.0.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/slf4j/jul-to-slf4j/1.7.25/jul-to-slf4j-1.7.25.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-json/2.0.6.RELEASE/spring-boot-starter-json-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/core/jackson-databind/2.9.7/jackson-databind-2.9.7.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/core/jackson-core/2.9.7/jackson-core-2.9.7.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.9.7/jackson-datatype-jdk8-2.9.7.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.9.7/jackson-datatype-jsr310-2.9.7.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/module/jackson-module-parameter-names/2.9.7/jackson-module-parameter-names-2.9.7.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-tomcat/2.0.6.RELEASE/spring-boot-starter-tomcat-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/tomcat/embed/tomcat-embed-core/8.5.34/tomcat-embed-core-8.5.34.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/tomcat/embed/tomcat-embed-el/8.5.34/tomcat-embed-el-8.5.34.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/tomcat/embed/tomcat-embed-websocket/8.5.34/tomcat-embed-websocket-8.5.34.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/hibernate/validator/hibernate-validator/6.0.13.Final/hibernate-validator-6.0.13.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/javax/validation/validation-api/2.0.1.Final/validation-api-2.0.1.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/jboss/logging/jboss-logging/3.3.2.Final/jboss-logging-3.3.2.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-web/5.0.10.RELEASE/spring-web-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-beans/5.0.10.RELEASE/spring-beans-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-webmvc/5.0.10.RELEASE/spring-webmvc-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-expression/5.0.10.RELEASE/spring-expression-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-core/5.0.10.RELEASE/spring-core-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-jcl/5.0.10.RELEASE/spring-jcl-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/projectlombok/lombok/1.16.22/lombok-1.16.22.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/alibaba/fastjson/1.2.60/fastjson-1.2.60.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/httpcomponents/httpclient/4.5.3/httpclient-4.5.3.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/httpcomponents/httpcore/4.4.10/httpcore-4.4.10.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/commons-codec/commons-codec/1.11/commons-codec-1.11.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/httpcomponents/httpmime/4.5.3/httpmime-4.5.3.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/httpcomponents/httpasyncclient/4.1/httpasyncclient-4.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/httpcomponents/httpcore-nio/4.4.10/httpcore-nio-4.4.10.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-aop/2.0.6.RELEASE/spring-boot-starter-aop-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-aop/5.0.10.RELEASE/spring-aop-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/aspectj/aspectjweaver/1.8.13/aspectjweaver-1.8.13.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/commons/commons-lang3/3.6/commons-lang3-3.6.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-data-redis/2.0.6.RELEASE/spring-boot-starter-data-redis-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/data/spring-data-redis/2.0.11.RELEASE/spring-data-redis-2.0.11.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/data/spring-data-keyvalue/2.0.11.RELEASE/spring-data-keyvalue-2.0.11.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/data/spring-data-commons/2.0.11.RELEASE/spring-data-commons-2.0.11.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-tx/5.0.10.RELEASE/spring-tx-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-oxm/5.0.10.RELEASE/spring-oxm-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/lettuce/lettuce-core/5.0.5.RELEASE/lettuce-core-5.0.5.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/projectreactor/reactor-core/3.1.10.RELEASE/reactor-core-3.1.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/reactivestreams/reactive-streams/1.0.2/reactive-streams-1.0.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-common/4.1.29.Final/netty-common-4.1.29.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-transport/4.1.29.Final/netty-transport-4.1.29.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-buffer/4.1.29.Final/netty-buffer-4.1.29.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-resolver/4.1.29.Final/netty-resolver-4.1.29.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-handler/4.1.29.Final/netty-handler-4.1.29.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-codec/4.1.29.Final/netty-codec-4.1.29.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/springfox/springfox-swagger2/2.9.2/springfox-swagger2-2.9.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/swagger/swagger-annotations/1.5.20/swagger-annotations-1.5.20.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/swagger/swagger-models/1.5.20/swagger-models-1.5.20.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/core/jackson-annotations/2.9.0/jackson-annotations-2.9.0.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/springfox/springfox-spi/2.9.2/springfox-spi-2.9.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/springfox/springfox-core/2.9.2/springfox-core-2.9.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/springfox/springfox-schema/2.9.2/springfox-schema-2.9.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/springfox/springfox-swagger-common/2.9.2/springfox-swagger-common-2.9.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/springfox/springfox-spring-web/2.9.2/springfox-spring-web-2.9.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/classmate/1.3.4/classmate-1.3.4.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/plugin/spring-plugin-core/1.2.0.RELEASE/spring-plugin-core-1.2.0.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/plugin/spring-plugin-metadata/1.2.0.RELEASE/spring-plugin-metadata-1.2.0.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/mapstruct/mapstruct/1.2.0.Final/mapstruct-1.2.0.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/springfox/springfox-swagger-ui/2.9.2/springfox-swagger-ui-2.9.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/junit/junit/4.12/junit-4.12.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/mockito/mockito-core/2.15.0/mockito-core-2.15.0.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/net/bytebuddy/byte-buddy/1.7.11/byte-buddy-1.7.11.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/net/bytebuddy/byte-buddy-agent/1.7.11/byte-buddy-agent-1.7.11.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/objenesis/objenesis/2.6/objenesis-2.6.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-configuration-processor/2.0.6.RELEASE/spring-boot-configuration-processor-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/commons-beanutils/commons-beanutils/1.9.3/commons-beanutils-1.9.3.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/commons-logging/commons-logging/1.2/commons-logging-1.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/commons-collections/commons-collections/3.2.2/commons-collections-3.2.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/commons/commons-pool2/2.6.1/commons-pool2-2.6.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/commons-net/commons-net/3.6/commons-net-3.6.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/guava/guava/23.0/guava-23.0.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/code/findbugs/jsr305/1.3.9/jsr305-1.3.9.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/errorprone/error_prone_annotations/2.0.18/error_prone_annotations-2.0.18.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/j2objc/j2objc-annotations/1.1/j2objc-annotations-1.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/codehaus/mojo/animal-sniffer-annotations/1.14/animal-sniffer-annotations-1.14.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/dom4j/dom4j/1.6.1/dom4j-1.6.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/xml-apis/xml-apis/1.4.01/xml-apis-1.4.01.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-mail/2.0.6.RELEASE/spring-boot-starter-mail-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-context/5.0.10.RELEASE/spring-context-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-context-support/5.0.10.RELEASE/spring-context-support-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/sun/mail/javax.mail/1.6.2/javax.mail-1.6.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/javax/activation/activation/1.1/activation-1.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/yaml/snakeyaml/1.25/snakeyaml-1.25.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/h2database/h2/1.4.199/h2-1.4.199.jar" enabled="true" runInBatchMode="false"/>
</factorypath>

View file

@ -0,0 +1,3 @@
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding/<project>=UTF-8

View file

@ -0,0 +1,4 @@
eclipse.preferences.version=1
org.eclipse.jdt.apt.aptEnabled=true
org.eclipse.jdt.apt.genSrcDir=target/generated-sources/annotations
org.eclipse.jdt.apt.genTestSrcDir=target/generated-test-sources/test-annotations

View file

@ -0,0 +1,10 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
org.eclipse.jdt.core.compiler.processAnnotations=enabled
org.eclipse.jdt.core.compiler.release=disabled
org.eclipse.jdt.core.compiler.source=1.8

View file

@ -0,0 +1,4 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>bcp-install</artifactId>
<groupId>com.cgb</groupId>
<version>1.0.0-RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>bcp-install-api</artifactId>
<version>1.0.0-RELEASE</version>
<dependencies>
<dependency>
<groupId>com.cgb</groupId>
<artifactId>bcp-install-biz</artifactId>
<version>1.0.0-RELEASE</version>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,341 @@
package com.cgb.bcpinstall.api.controller;
import com.alibaba.fastjson.JSONObject;
import com.cgb.bcpinstall.biz.InstallBiz;
import com.cgb.bcpinstall.biz.RolesBiz;
import com.cgb.bcpinstall.common.annotation.InvokeLog;
import com.cgb.bcpinstall.common.entity.*;
import com.cgb.bcpinstall.common.response.BaseResponse;
import com.cgb.bcpinstall.common.response.HttpInstallResponse;
import com.cgb.bcpinstall.common.response.ResponseCode;
import com.cgb.bcpinstall.common.util.FileUtil;
import com.cgb.bcpinstall.service.FileService;
import com.cgb.bcpinstall.service.ModeService;
import com.cgb.bcpinstall.service.UpdateService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.*;
import java.net.URLEncoder;
import java.util.List;
@Slf4j
@RestController
@RequestMapping(value = "/v1/install", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@Api("安装管理")
public class InstallController {
@Autowired
private RolesBiz rolesBiz;
@Autowired
private InstallBiz installBiz;
@Autowired
private ModeService modeService;
@Autowired
private FileService fileService;
@Autowired
private UpdateService updateService;
/**
* 从节点从主节点下载安装包
* <p>
* 压缩包内容格式以下面格式进行组织目录可以是其中一部分
* |
* |____crypto-config
* | |_____ordererOrganizations
* | |_____peerOrganizations
* |____order
* | |_____docker-compose-orderer.yaml
* | |_____start-orderer.sh
* |____peer
* | |_____docker-compose-peer.yaml
* | |_____start-peer.sh
* |____backend
* | |____bcp-app-mgr
* | | |____resources
* | | | |____networkconfigs
* | | | |____users
* | | | |____initData.yaml
* | | |____start-backend.sh
* |____web
* | |____bcp-app-web
* | | |____vue.config.js
* | | |____start-web.sh
*
* @param request
* @param response
* @return
*/
@RequestMapping("/getPackage/{os}")
@ApiOperation(value = "下载安装文件")
@InvokeLog(name = "getInstallPackage", description = "下载安装文件")
public void getInstallData(@PathVariable("os") String osType, HttpServletRequest request, HttpServletResponse response) {
String remoteAddr = request.getRemoteAddr();
log.info(String.format("从节点 %s 开始下载安装包", remoteAddr));
BaseResponse downloadResponse = new BaseResponse();
OSEnum osEnum = null;
try {
osEnum = OSEnum.valueOf(osType);
} catch (Exception e) {
log.error("解析系统类型异常", e);
e.printStackTrace();
}
if (osEnum == null) {
log.error(String.format("从节点系统类型错误: %s", osType));
downloadResponse.setCode(ResponseCode.Fail);
downloadResponse.setMsg("不支持指定的系统类型: " + osType);
setErrorResult(response, downloadResponse);
return;
}
List<RoleEnum> roleList = rolesBiz.getRole(remoteAddr);
// 根据角色准备不同的压缩包
String filePath = fileService.packInstallFiles(remoteAddr, roleList, null);
if (StringUtils.isEmpty(filePath)) {
downloadResponse.setCode(ResponseCode.Fail);
downloadResponse.setMsg("打包安装文件失败");
setErrorResult(response, downloadResponse);
return;
}
File downloadFile = new File(filePath);
FileInputStream is = null;
OutputStream os = null;
try {
// 配置文件下载
response.setHeader("content-type", "application/octet-stream");
response.setContentType("application/octet-stream");
// 下载文件能正常显示中文
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("InstallPackage.tar.gz", "UTF-8"));
is = new FileInputStream(downloadFile);
os = response.getOutputStream();
IOUtils.copy(is, os);
// 修改服务器对应的状态
log.info(String.format("设置从节点 %s 状态为下载完成", remoteAddr));
this.rolesBiz.setServerStatus(remoteAddr, InstallStatusEnum.DOWNLOADED);
} catch (FileNotFoundException e) {
log.error("下载文件不存在", e);
e.printStackTrace();
downloadResponse.setCode(ResponseCode.Fail);
downloadResponse.setMsg("下载文件不存在");
setErrorResult(response, downloadResponse);
} catch (IOException e) {
log.error("获取HttpServletResponse输出流发生异常", e);
e.printStackTrace();
downloadResponse.setCode(ResponseCode.Fail);
downloadResponse.setMsg("获取HttpServletResponse输出流发生异常");
setErrorResult(response, downloadResponse);
} finally {
IOUtils.closeQuietly(is);
IOUtils.closeQuietly(os);
}
}
@PostMapping("/pushPackage")
@ApiOperation(value = "下载安装文件")
@InvokeLog(name = "pushInstallPackage", description = "推送安装文件")
public HttpInstallResponse pushInstallPackage(HttpServletRequest request) {
log.info("准备接收主节点推送的安装包");
this.installBiz.setMasterServer("http://" + request.getRemoteAddr() + ":8080");
HttpInstallResponse response = new HttpInstallResponse();
try {
String filePath = this.installBiz.getInstallPackageFilePath();
Part part = request.getPart("file");
part.write(filePath);
this.installBiz.installPackageReady();
} catch (Exception e) {
log.error("接收安装包异常", e);
response.setCode(ResponseCode.Fail.getCode());
e.printStackTrace();
}
return response;
}
private void setErrorResult(HttpServletResponse httpServletResponse, BaseResponse res) {
httpServletResponse.setContentType("application/json; charset=utf-8");
httpServletResponse.setStatus(HttpServletResponse.SC_OK);
try {
PrintWriter writer = httpServletResponse.getWriter();
writer.print(JSONObject.toJSONString(res));
writer.close();
httpServletResponse.flushBuffer();
} catch (IOException ie) {
ie.printStackTrace();
}
}
/**
* 主节点发送给从节点开始安装
*
* @param request
* @return
*/
@PostMapping("/start")
@ApiOperation(value = "开始安装")
@InvokeLog(name = "doInstall", description = "开始安装")
public HttpInstallResponse doInstall(HttpServletRequest request) {
HttpInstallResponse response = new HttpInstallResponse();
log.info("从节点收到安装指令");
try {
//获取安装指令实例
Part contentPart = request.getPart("content");
ByteArrayOutputStream os = new ByteArrayOutputStream();
IOUtils.copy(contentPart == null ? request.getInputStream() : contentPart.getInputStream(), os);
String content = os.toString();
InstallCmd installCmd = JSONObject.parseObject(content, InstallCmd.class);
this.installBiz.setMasterServer("http://" + request.getRemoteAddr() + ":8080");
this.installBiz.slaveInstall(installCmd.getRole(), installCmd.getRolePorts(), installCmd.getHosts(), installCmd.getRoleFolderName());
} catch (Exception e) {
e.printStackTrace();
response.setCode(ResponseCode.Fail.getCode());
}
return response;
}
@PostMapping("/backendStatus")
@ApiOperation(value = "检查管理后台状态")
@InvokeLog(name = "doCheckBackendStatus", description = "检查管理后台状态")
public HttpInstallResponse checkBackendStatus(HttpServletRequest request) {
HttpInstallResponse response = new HttpInstallResponse();
String filePath = modeService.getInstallPath() + "fetchBackendInit.sh";
try {
Part part = request.getPart("file");
part.write(filePath);
} catch (IOException | ServletException e) {
e.printStackTrace();
response.setCode(ResponseCode.Fail.getCode());
return response;
}
if (modeService.checkBackendInitFinished(null, filePath)) {
response.setCode(ResponseCode.SUCCESS.getCode());
} else {
response.setCode(ResponseCode.BOOTING.getCode());
}
return response;
}
@PostMapping("/remove")
@ApiOperation(value = "移除节点")
@InvokeLog(name = "doRemove", description = "移除节点")
public HttpInstallResponse doRemove(HttpServletRequest request) {
HttpInstallResponse response = new HttpInstallResponse();
try {
Part contentPart = request.getPart("content");
ByteArrayOutputStream os = new ByteArrayOutputStream();
IOUtils.copy(contentPart == null ? request.getInputStream() : contentPart.getInputStream(), os);
String content = os.toString();
RemoveCmd removeCmd = JSONObject.parseObject(content, RemoveCmd.class);
String filePath = modeService.getInstallPath();
if (!filePath.endsWith(File.separator)) {
filePath = filePath + File.separator;
}
if (removeCmd.getRole() == RoleEnum.PEER || removeCmd.getRole() == RoleEnum.ORDER) {
filePath = filePath + "stopNode.sh";
Part part = request.getPart("file");
part.write(filePath);
}
log.info("从节点收到移除指令");
String domain = removeCmd.getRole() == RoleEnum.ORDER ? removeCmd.getOrdererDomain() : removeCmd.getPeerDomain();
updateService.removeNode(removeCmd.getRole(), domain, removeCmd.getHostNames(), removeCmd.getPorts());
} catch (Exception e) {
e.printStackTrace();
response.setCode(ResponseCode.Fail.getCode());
}
return new HttpInstallResponse();
}
/**
* 主要用于节点更新
*
* @param request
* @return
*/
@PostMapping("/update")
@ApiOperation(value = "更新节点")
@InvokeLog(name = "doUpdate", description = "更新节点")
public HttpInstallResponse doUpdate(HttpServletRequest request) {
HttpInstallResponse response = new HttpInstallResponse();
try {
Part contentPart = request.getPart("content");
ByteArrayOutputStream os = new ByteArrayOutputStream();
IOUtils.copy(contentPart == null ? request.getInputStream() : contentPart.getInputStream(), os);
String content = os.toString();
UpdateCmd cmd = JSONObject.parseObject(content, UpdateCmd.class);
Part part = request.getPart("file");
installBiz.handleUpdate(cmd, part);
} catch (Exception e) {
log.error("接收更新指令异常", e);
response.setCode(ResponseCode.Fail.getCode());
e.printStackTrace();
}
return response;
}
/**
* 主节点接收从节点发过来的调用
*
* @param result
* @param request
* @return
*/
@PostMapping("/finished")
@ApiOperation(value = "完成安装")
@InvokeLog(name = "installFinished", description = "完成安装")
public HttpInstallResponse installFinished(@RequestBody InstallResult result, HttpServletRequest request) {
log.info(String.format("从节点 %s 完成安装", request.getRemoteAddr()));
modeService.updateInstallResult(request.getRemoteAddr(), result, null);
return new HttpInstallResponse();
}
/**
* 主节点向从节点发起的调用通知安装结束
*
* @param result
* @return
*/
@PostMapping("/end")
@ApiOperation(value = "结束安装")
@InvokeLog(name = "endInstall", description = "结束安装")
public HttpInstallResponse endInstall(@RequestBody EndCmd result) {
log.info("从节点收到结束安装指令");
this.installBiz.doEnd();
return new HttpInstallResponse();
}
}

View file

@ -0,0 +1,51 @@
package com.cgb.bcpinstall.api.controller;
import com.cgb.bcpinstall.biz.InstallBiz;
import com.cgb.bcpinstall.common.annotation.InvokeLog;
import com.cgb.bcpinstall.common.entity.RoleRegEntity;
import com.cgb.bcpinstall.common.response.BaseResponse;
import com.cgb.bcpinstall.common.response.HttpInstallResponse;
import com.cgb.bcpinstall.service.ModeService;
import com.cgb.bcpinstall.service.RoleService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
@Slf4j
@RestController
@RequestMapping(value = "/v1/reg", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@Api("注册管理")
public class RegisterController {
@Autowired
private RoleService roleService;
/**
* 从节点向主节点注册角色主节点会根据其 ip 地址找出其所有角色并进行缓存
*
* @param roleRegEntity
* @param request
* @return
*/
@Deprecated
@PostMapping("/role")
@ApiOperation(value = "注册从服务器角色")
@InvokeLog(name = "registerServerRole", description = "注册从服务器角色")
public HttpInstallResponse regRole(@RequestBody RoleRegEntity roleRegEntity, HttpServletRequest request) {
String remoteAddr = request.getRemoteAddr();
log.info(String.format("从节点 %s 开始注册", remoteAddr));
roleService.addServerRole(remoteAddr, roleRegEntity.getServerPort(),null);
return new HttpInstallResponse();
}
}

View file

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="target/generated-sources/annotations">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View file

@ -0,0 +1,102 @@
<factorypath>
<factorypathentry kind="VARJAR" id="M2_REPO/commons-io/commons-io/1.3.2/commons-io-1.3.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/commons/commons-compress/1.18/commons-compress-1.18.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/httpcomponents/httpmime/4.5.3/httpmime-4.5.3.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-web/2.0.6.RELEASE/spring-boot-starter-web-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter/2.0.6.RELEASE/spring-boot-starter-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot/2.0.6.RELEASE/spring-boot-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-autoconfigure/2.0.6.RELEASE/spring-boot-autoconfigure-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-logging/2.0.6.RELEASE/spring-boot-starter-logging-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/logging/log4j/log4j-to-slf4j/2.10.0/log4j-to-slf4j-2.10.0.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/logging/log4j/log4j-api/2.10.0/log4j-api-2.10.0.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/slf4j/jul-to-slf4j/1.7.25/jul-to-slf4j-1.7.25.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-json/2.0.6.RELEASE/spring-boot-starter-json-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/core/jackson-databind/2.9.7/jackson-databind-2.9.7.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/core/jackson-core/2.9.7/jackson-core-2.9.7.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.9.7/jackson-datatype-jdk8-2.9.7.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.9.7/jackson-datatype-jsr310-2.9.7.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/module/jackson-module-parameter-names/2.9.7/jackson-module-parameter-names-2.9.7.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-tomcat/2.0.6.RELEASE/spring-boot-starter-tomcat-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/tomcat/embed/tomcat-embed-core/8.5.34/tomcat-embed-core-8.5.34.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/tomcat/embed/tomcat-embed-el/8.5.34/tomcat-embed-el-8.5.34.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/tomcat/embed/tomcat-embed-websocket/8.5.34/tomcat-embed-websocket-8.5.34.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/hibernate/validator/hibernate-validator/6.0.13.Final/hibernate-validator-6.0.13.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/javax/validation/validation-api/2.0.1.Final/validation-api-2.0.1.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/jboss/logging/jboss-logging/3.3.2.Final/jboss-logging-3.3.2.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-web/5.0.10.RELEASE/spring-web-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-beans/5.0.10.RELEASE/spring-beans-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-webmvc/5.0.10.RELEASE/spring-webmvc-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-expression/5.0.10.RELEASE/spring-expression-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-core/5.0.10.RELEASE/spring-core-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-jcl/5.0.10.RELEASE/spring-jcl-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/projectlombok/lombok/1.16.22/lombok-1.16.22.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/alibaba/fastjson/1.2.60/fastjson-1.2.60.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/httpcomponents/httpclient/4.5.3/httpclient-4.5.3.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/httpcomponents/httpcore/4.4.10/httpcore-4.4.10.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/commons-codec/commons-codec/1.11/commons-codec-1.11.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/httpcomponents/httpasyncclient/4.1/httpasyncclient-4.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/httpcomponents/httpcore-nio/4.4.10/httpcore-nio-4.4.10.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-aop/2.0.6.RELEASE/spring-boot-starter-aop-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-aop/5.0.10.RELEASE/spring-aop-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/aspectj/aspectjweaver/1.8.13/aspectjweaver-1.8.13.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/commons/commons-lang3/3.6/commons-lang3-3.6.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-data-redis/2.0.6.RELEASE/spring-boot-starter-data-redis-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/data/spring-data-redis/2.0.11.RELEASE/spring-data-redis-2.0.11.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/data/spring-data-keyvalue/2.0.11.RELEASE/spring-data-keyvalue-2.0.11.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/data/spring-data-commons/2.0.11.RELEASE/spring-data-commons-2.0.11.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-tx/5.0.10.RELEASE/spring-tx-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-oxm/5.0.10.RELEASE/spring-oxm-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/lettuce/lettuce-core/5.0.5.RELEASE/lettuce-core-5.0.5.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/projectreactor/reactor-core/3.1.10.RELEASE/reactor-core-3.1.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/reactivestreams/reactive-streams/1.0.2/reactive-streams-1.0.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-common/4.1.29.Final/netty-common-4.1.29.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-transport/4.1.29.Final/netty-transport-4.1.29.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-buffer/4.1.29.Final/netty-buffer-4.1.29.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-resolver/4.1.29.Final/netty-resolver-4.1.29.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-handler/4.1.29.Final/netty-handler-4.1.29.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-codec/4.1.29.Final/netty-codec-4.1.29.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/springfox/springfox-swagger2/2.9.2/springfox-swagger2-2.9.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/swagger/swagger-annotations/1.5.20/swagger-annotations-1.5.20.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/swagger/swagger-models/1.5.20/swagger-models-1.5.20.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/core/jackson-annotations/2.9.0/jackson-annotations-2.9.0.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/springfox/springfox-spi/2.9.2/springfox-spi-2.9.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/springfox/springfox-core/2.9.2/springfox-core-2.9.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/springfox/springfox-schema/2.9.2/springfox-schema-2.9.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/springfox/springfox-swagger-common/2.9.2/springfox-swagger-common-2.9.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/springfox/springfox-spring-web/2.9.2/springfox-spring-web-2.9.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/classmate/1.3.4/classmate-1.3.4.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/plugin/spring-plugin-core/1.2.0.RELEASE/spring-plugin-core-1.2.0.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/plugin/spring-plugin-metadata/1.2.0.RELEASE/spring-plugin-metadata-1.2.0.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/mapstruct/mapstruct/1.2.0.Final/mapstruct-1.2.0.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/springfox/springfox-swagger-ui/2.9.2/springfox-swagger-ui-2.9.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/junit/junit/4.12/junit-4.12.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/mockito/mockito-core/2.15.0/mockito-core-2.15.0.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/net/bytebuddy/byte-buddy/1.7.11/byte-buddy-1.7.11.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/net/bytebuddy/byte-buddy-agent/1.7.11/byte-buddy-agent-1.7.11.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/objenesis/objenesis/2.6/objenesis-2.6.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-configuration-processor/2.0.6.RELEASE/spring-boot-configuration-processor-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/commons-beanutils/commons-beanutils/1.9.3/commons-beanutils-1.9.3.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/commons-logging/commons-logging/1.2/commons-logging-1.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/commons-collections/commons-collections/3.2.2/commons-collections-3.2.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/commons/commons-pool2/2.6.1/commons-pool2-2.6.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/commons-net/commons-net/3.6/commons-net-3.6.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/guava/guava/23.0/guava-23.0.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/code/findbugs/jsr305/1.3.9/jsr305-1.3.9.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/errorprone/error_prone_annotations/2.0.18/error_prone_annotations-2.0.18.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/j2objc/j2objc-annotations/1.1/j2objc-annotations-1.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/codehaus/mojo/animal-sniffer-annotations/1.14/animal-sniffer-annotations-1.14.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/dom4j/dom4j/1.6.1/dom4j-1.6.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/xml-apis/xml-apis/1.4.01/xml-apis-1.4.01.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-mail/2.0.6.RELEASE/spring-boot-starter-mail-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-context/5.0.10.RELEASE/spring-context-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-context-support/5.0.10.RELEASE/spring-context-support-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/sun/mail/javax.mail/1.6.2/javax.mail-1.6.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/javax/activation/activation/1.1/activation-1.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/yaml/snakeyaml/1.25/snakeyaml-1.25.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/h2database/h2/1.4.199/h2-1.4.199.jar" enabled="true" runInBatchMode="false"/>
</factorypath>

View file

@ -0,0 +1,3 @@
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding/<project>=UTF-8

View file

@ -0,0 +1,4 @@
eclipse.preferences.version=1
org.eclipse.jdt.apt.aptEnabled=true
org.eclipse.jdt.apt.genSrcDir=target/generated-sources/annotations
org.eclipse.jdt.apt.genTestSrcDir=target/generated-test-sources/test-annotations

View file

@ -0,0 +1,10 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
org.eclipse.jdt.core.compiler.processAnnotations=enabled
org.eclipse.jdt.core.compiler.release=disabled
org.eclipse.jdt.core.compiler.source=1.8

View file

@ -0,0 +1,4 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>bcp-install</artifactId>
<groupId>com.cgb</groupId>
<version>1.0.0-RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>bcp-install-biz</artifactId>
<version>1.0.0-RELEASE</version>
<dependencies>
<dependency>
<groupId>com.cgb</groupId>
<artifactId>bcp-install-common</artifactId>
<version>1.0.0-RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,76 @@
package com.cgb.bcpinstall.biz;
import com.cgb.bcpinstall.common.entity.init.InitConfigEntity;
import com.cgb.bcpinstall.common.response.BaseResponse;
import com.cgb.bcpinstall.common.response.ResponseCode;
import com.cgb.bcpinstall.common.util.FileUtil;
import com.cgb.bcpinstall.config.ConfigFileGen;
import com.cgb.bcpinstall.service.InitConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.FileNotFoundException;
@Slf4j
@Component
public class InitializeBiz {
@Autowired
private InitConfigService initConfigService;
@Autowired
private ConfigFileGen configFileGen;
@Value("${init.config}")
private String initConfigFile;
@Value("${init.dir}")
private String initDir;
@Value("${init.yes}")
private int doInit;
public boolean needInit() {
return this.doInit == 1;
}
public BaseResponse initialize() {
BaseResponse response = new BaseResponse();
if (!needInit()) {
response.setCode(ResponseCode.Fail);
return response;
}
this.initDir = FileUtil.reviseDir(this.initDir);
this.initConfigFile = FileUtil.reviseDir(this.initConfigFile);
try {
InitConfigEntity configEntity = initConfigService.parseConfigFile(this.initConfigFile);
if (configEntity == null) {
response.setCode(ResponseCode.Fail);
response.setMsg("解析初始化配置文件失败");
return response;
}
if (!initConfigService.isCorrectConfig(configEntity)) {
log.error("配置文件中相关配置项出错或为空");
response.setCode(ResponseCode.Fail);
response.setMsg("配置文件中相关配置项出错或为空");
return response;
}
configFileGen.createConfigFile(configEntity);
} catch (FileNotFoundException fe) {
log.error("文件不存在异常", fe);
response.setCode(ResponseCode.Fail);
fe.printStackTrace();
} catch (Exception e) {
log.error("初始化发生异常", e);
response.setCode(ResponseCode.Fail);
e.printStackTrace();
}
return response;
}
}

View file

@ -0,0 +1,266 @@
package com.cgb.bcpinstall.biz;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cgb.bcpinstall.common.entity.*;
import com.cgb.bcpinstall.common.entity.init.InitConfigEntity;
import com.cgb.bcpinstall.common.response.HttpInstallResponse;
import com.cgb.bcpinstall.common.response.ResponseCode;
import com.cgb.bcpinstall.common.util.*;
import com.cgb.bcpinstall.config.GlobalConfig;
import com.cgb.bcpinstall.db.CheckPointDb;
import com.cgb.bcpinstall.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.yaml.snakeyaml.Yaml;
import javax.servlet.http.Part;
import java.io.*;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
@Slf4j
@Service
public class InstallBiz {
private static final String INSTALL_PACKAGE_FILE_NAME = "InstallPackage.tar.gz";
@Autowired
private EnvironmentService environmentService;
@Autowired
private InstallService installService;
@Autowired
private InitConfigService initConfigService;
@Autowired
private GlobalConfig globalConfig;
@Autowired
private HttpClientUtil httpClient;
@Autowired
private CheckPointDb checkPointDb;
@Autowired
private ModeService modeService;
@Value("${init.config}")
private String initConfigFile;
@Value("${install.mode}")
private String installMode;
@Value("${server.port}")
private String httpServerPort;
private String masterServer;
private InitConfigEntity configEntity;
private AtomicBoolean finished = new AtomicBoolean(false);
private Thread task;
public void start() {
this.task = new Thread(this::doInstallThread);
this.task.start();
}
public String getInstallPackageFilePath() {
FileUtil.makeFilePath(modeService.getInstallPath(), false);
return modeService.getInstallPath() + INSTALL_PACKAGE_FILE_NAME;
}
public void setMasterServer(String server) {
this.masterServer = server;
}
/**
* 安装线程的主函数
*/
private void doInstallThread() {
this.initConfigFile = FileUtil.reviseDir(this.initConfigFile);
// http 服务端口添加防火墙
environmentService.addPortIntoFirewall(this.httpServerPort);
// 主节点
if (this.globalConfig.getMaster() == 1) {
File configFile = new File(this.initConfigFile);
if (!configFile.exists() || !configFile.isFile()) {
log.error(String.format("initconfig.propertise(传入的路径:%s)文件不存在, 请按任意键结束,重新运行", this.initConfigFile));
this.finished.set(true);
return;
}
try {
this.configEntity = initConfigService.parseConfigFile(this.initConfigFile);
if (configEntity == null) {
log.error("解析初始化配置文件失败");
this.doEnd();
return;
}
//校验配置信息格式
if (!initConfigService.isCorrectConfig(configEntity)) {
this.doEnd();
return;
}
if (this.configEntity.getOrdererHostConfig().size() < 3) {
log.error("orderer 节点不能少于3个请重新编辑配置文件结束安装");
this.doEnd();
return;
}
if (this.configEntity.getPeerHostConfig().size() < 2) {
log.error("peer 节点不能少于2个请重新编辑配置文件结束安装");
this.doEnd();
return;
}
InstallMode installModeAction = null;
if ("newInstall".equalsIgnoreCase(this.installMode)) {
installModeAction = (InstallMode) SpringUtil.getBean("newInstallBiz");
} else {
if (checkModifyInstall()) {
installModeAction = (InstallMode) SpringUtil.getBean("updateNetworkBiz");
} else {
System.out.println("在配置文件中没有找到需要更新的信息");
}
}
if (installModeAction != null) {
installModeAction.run(configEntity);
this.doEnd();
}
} catch (Exception e) {
log.error("安装过程发生异常", e);
e.printStackTrace();
}
}
}
/**
* 根据现有安装的记录计算增量内容
*
* @return true 为增量/减量安装false 为全新安装
*/
private boolean checkModifyInstall() {
try {
return !this.checkPointDb.nodesTableEmpty();
} catch (SQLException e) {
log.error("查询本地数据库失败", e);
e.printStackTrace();
}
return false;
}
/**
* 启动从节点安装线程
*
* @param role
*/
public void slaveInstall(RoleEnum role, List<String> ports, Map<String, String> hosts, String roleFolderName) {
new Thread(() -> {
log.info(String.format("从节点开始进行角色 %s 的安装", role.name()));
if (this.startInstall(role, ports, hosts, roleFolderName)) {
InstallResult result = new InstallResult();
result.setRole(role);
result.setSuccess(true);
try {
do {
String res = httpClient.postJson(this.masterServer + "/v1/install/finished", JSONObject.toJSONString(result), false);
if (!StringUtils.isEmpty(res)) {
HttpInstallResponse response = JSONObject.parseObject(res, HttpInstallResponse.class);
if (ResponseCode.SUCCESS.getCode().equals(response.getCode())) {
log.info(String.format("向主节点报告安装 %s 状态成功", role.name()));
break;
}
}
log.info(String.format("向主节点报告安装 %s 状态失败,稍后重试...", role.name()));
try {
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
}
} while (true);
} catch (Exception e) {
log.error("向主服务器发送安装完成状态异常", e);
e.printStackTrace();
}
}
}).start();
}
private boolean startInstall(RoleEnum role, List<String> rolePorts, Map<String, String> hosts, String roleFolderName) {
return installService.startRole(role, rolePorts, hosts, roleFolderName);
}
public boolean isFinished() {
return this.finished.get();
}
public void installPackageReady() {
String packageFilePath = modeService.getInstallPath() + INSTALL_PACKAGE_FILE_NAME;
FileUtil.tarGzDecompress(packageFilePath, modeService.getInstallPath(), false);
}
/**
* 修改 orderer 容器配置后重启 docker InstallController 调用
*
* @param updateCmd
*/
public void updateOrderers(UpdateCmd updateCmd) {
for (String orderName : updateCmd.getPeerHostConfig().keySet()) {
String ipPort = updateCmd.getPeerHostConfig().get(orderName);
String ip = ipPort.substring(0, ipPort.lastIndexOf(":"));
if ("127.0.0.1".equals(ip)) {
ip = NetUtil.getMyNormalIP();
}
updateOrderConfig(orderName, ip, updateCmd.getCurrentHost());
}
}
private void updateOrderConfig(String newOrderName, String ip, String currentOrdererName) {
try {
ProcessUtil.Result result = ProcessUtil.execCmd("docker exec " + currentOrdererName + " bash updateOrdererHost.sh " + newOrderName + " " + ip, null, modeService.getInstallPath());
if (result.getCode() == 0) {
log.info(String.format("更新 docker 容器 %s 的 Hosts 成功: ", currentOrdererName));
} else {
log.error(String.format("更新 docker 容器 %s 的 Hosts 失败: " + result.getData(), currentOrdererName));
}
} catch (Exception e) {
log.error(String.format("更新 docker 容器 %s 的 HostsPath 异常", currentOrdererName), e);
e.printStackTrace();
}
}
public void handleUpdate(UpdateCmd cmd, Part part) {
try {
if (cmd.getRole() == RoleEnum.ORDER) {
String filePath = "/var/run/updateOrdererHost.sh";
File updateHostFile = new File(filePath);
if (updateHostFile.exists()) {
updateHostFile.delete();
}
part.write(filePath);
this.updateOrderers(cmd);
}
this.doEnd();
} catch (Exception e) {
e.printStackTrace();
}
}
public void doEnd() {
this.finished.set(true);
System.out.println("*****安装服务已完成*****");
}
}

View file

@ -0,0 +1,15 @@
package com.cgb.bcpinstall.biz;
import com.cgb.bcpinstall.common.entity.init.InitConfigEntity;
/**
* @author zheng.li
* @date 2020/2/3 11:35
*/
public interface InstallMode {
/**
* 执行mode
* @param configEntity
*/
void run(InitConfigEntity configEntity);
}

View file

@ -0,0 +1,244 @@
package com.cgb.bcpinstall.biz;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cgb.bcpinstall.common.entity.*;
import com.cgb.bcpinstall.common.entity.init.InitConfigEntity;
import com.cgb.bcpinstall.common.response.HttpInstallResponse;
import com.cgb.bcpinstall.common.response.ResponseCode;
import com.cgb.bcpinstall.common.util.*;
import com.cgb.bcpinstall.config.GlobalConfig;
import com.cgb.bcpinstall.db.CheckPointDb;
import com.cgb.bcpinstall.db.table.NodeDO;
import com.cgb.bcpinstall.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.yaml.snakeyaml.Yaml;
import java.io.*;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
/**
* @author zheng.li
* @date 2020/2/2 13:30
*/
@Service
@Slf4j
public class NewInstallBiz implements InstallMode {
@Autowired
private RolesBiz rolesBiz;
@Autowired
private GlobalConfig globalConfig;
@Autowired
private ModeService modeService;
@Autowired
private RoleService roleService;
@Autowired
private RemoteService remoteService;
@Autowired
private InstallService installService;
@Autowired
private FileService fileService;
@Value("${server.port}")
private String httpServerPort;
@Override
public void run(InitConfigEntity configEntity) {
log.info("主节点开始安装流程...");
// 将所有的从节点注册到角色列表
registerSlaveServers(configEntity);
log.info("主节点添加到角色列表");
// 也把自己添加到角色列表里
List<String> allMyIps = NetUtil.getLocalIPList();
for (String ip : allMyIps) {
roleService.addServerRole(ip, this.httpServerPort, configEntity);
}
List<RoleEnum> allMyRoles = this.getAllMyRoles();
log.info("主节点复制安装文件");
// 为自己复制安装文件
fileService.copyInstallFiles(allMyIps, allMyRoles, configEntity);
// 修改自己的状态
log.info("主节点修改安装状态");
for (String ip : allMyIps) {
this.rolesBiz.setServerStatus(ip, InstallStatusEnum.DOWNLOADED);
}
// 主节点需要所有的证书文件
fileService.masterCopyCryptoConfig();
// 启动 fabric 网络
if (this.globalConfig.getMaster() == 1) {
fileService.masterCopyConfigtxFile();
// 启动fabric网络
if (!createFabricGenesis(configEntity)) {
return;
}
}
log.info("将安装包推给每个从节点");
pushInstallPackages(configEntity);
log.info("安装 orderer");
// 首先安装 Orderer
installService.install(RoleEnum.ORDER, configEntity);
log.info("安装 peer");
// 安装 Peer
installService.install(RoleEnum.PEER, configEntity);
log.info("等待所有节点完成安装...");
int retryCount = 1;
int retryTotal = 7;
while (true) {
if (checkAllServersSuccess()) {
break;
}
if (retryCount == retryTotal) {
log.info("安装状态查询超时,部署可能出现异常,请排查!");
break;
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
retryCount++;
}
log.info("通知所有服务器安装结束");
// 通知所有服务器结束
Set<String> serverUrl = getServersUrl();
remoteService.notifyNodesToEnd(serverUrl);
}
private void registerSlaveServers(InitConfigEntity configEntity) {
List<String> slaveServers = parseAllSlaveIps(configEntity);
for (String ip : slaveServers) {
roleService.addServerRole(ip, "8080", configEntity);
}
}
private List<RoleEnum> getAllMyRoles() {
List<RoleEnum> roleList = new ArrayList<>();
Map<RoleEnum, List<ServerEntity>> allServers = this.rolesBiz.getRolesMap();
List<String> ipList = NetUtil.getLocalIPList();
for (String ip : ipList) {
for (RoleEnum role : allServers.keySet()) {
List<ServerEntity> serverList = allServers.get(role);
if (serverList.stream().anyMatch(s -> s.getHost().equals(ip))) {
roleList.add(role);
}
}
}
return roleList;
}
private boolean createFabricGenesis(InitConfigEntity configEntity) {
log.info("开始 fabric 创世");
String fabricDir = modeService.getInstallPath() + "channel-artifacts" + File.separator;
FileUtil.makeFilePath(fabricDir, true);
String sysChannelName = configEntity.getNetwork() + "-sys-channel";
String cmd = CacheUtil.getConfigtxgenFilePath() + " -profile SampleMultiNodeEtcdRaft -channelID " + sysChannelName + " -outputBlock " + fabricDir + "genesis.block";
log.info("生成创世块-执行命令:" + cmd);
try {
ProcessUtil.Result res = ProcessUtil.execCmd(cmd, null, modeService.getInstallPath());
if (res.getCode() == 0) {
log.info("创世成功");
return true;
} else {
log.warn("创世失败");
}
} catch (Exception e) {
log.error("生成创世块异常", e);
e.printStackTrace();
}
return false;
}
private void pushInstallPackages(InitConfigEntity configEntity) {
//获取所有的从节点ip
List<String> allSlaveIps = parseAllSlaveIps(configEntity);
//推送安装包
for (String slaveIp : allSlaveIps) {
log.info(String.format("向从节点 %s 推送安装包", slaveIp));
remoteService.pushSlaveInstallPackage(slaveIp, configEntity);
}
}
private boolean checkAllServersSuccess() {
// 检查是否所有服务器完成安装
Map<RoleEnum, List<ServerEntity>> rolesMap = this.rolesBiz.getRolesMap();
for (RoleEnum role : rolesMap.keySet()) {
List<ServerEntity> serverList = rolesMap.get(role);
for (ServerEntity s : serverList) {
if (s.getStatus() != InstallStatusEnum.SUCCESS) {
return false;
}
}
}
return true;
}
private Set<String> getServersUrl() {
Set<String> serverUrls = new HashSet<>();
Map<RoleEnum, List<ServerEntity>> rolesMap = this.rolesBiz.getRolesMap();
for (RoleEnum role : rolesMap.keySet()) {
List<ServerEntity> serverList = rolesMap.get(role);
for (ServerEntity s : serverList) {
if (!NetUtil.ipIsMine(s.getHost())) {
serverUrls.add(s.getHttpUrl());
}
}
}
return serverUrls;
}
private List<String> parseAllSlaveIps(InitConfigEntity configEntity) {
List<String> allSlaveIps = new ArrayList<>();
parseSlaveIps(allSlaveIps, configEntity.getOrdererHostConfig());
parseSlaveIps(allSlaveIps, configEntity.getPeerHostConfig());
return allSlaveIps;
}
private void parseSlaveIps(List<String> allSlaveIps, Map<String, String> hostConfig) {
for (String host : hostConfig.keySet()) {
String origIp = hostConfig.get(host);
int index = origIp.lastIndexOf(":");
String ip = origIp.substring(0, index);
if (!NetUtil.ipIsMine(ip)) {
allSlaveIps.add(ip);
}
}
}
}

View file

@ -0,0 +1,350 @@
package com.cgb.bcpinstall.biz;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cgb.bcpinstall.common.entity.*;
import com.cgb.bcpinstall.common.entity.init.InitConfigEntity;
import com.cgb.bcpinstall.common.response.HttpInstallResponse;
import com.cgb.bcpinstall.common.response.ResponseCode;
import com.cgb.bcpinstall.common.util.*;
import com.cgb.bcpinstall.config.ConfigFileGen;
import com.cgb.bcpinstall.config.FabricConfigGen;
import com.cgb.bcpinstall.config.configGenImpl.DockerConfigGenImpl;
import com.cgb.bcpinstall.db.CheckPointDb;
import com.cgb.bcpinstall.db.table.NodeDO;
import com.cgb.bcpinstall.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.*;
/**
* @author zheng.li
* @date 2020/2/3 10:54
*/
@Service
@Slf4j
public class OrdererExtendBiz {
@Autowired
private RolesBiz rolesBiz;
@Autowired
private HttpClientUtil httpClient;
@Autowired
private CheckPointDb checkPointDb;
@Autowired
private ModeService modeService;
@Autowired
private FileService fileService;
@Autowired
private UpdateService updateService;
@Autowired
private EnvironmentService environmentService;
@Autowired
private RemoteService remoteService;
@Autowired
private FabricCliService fabricCliService;
@Autowired
private InstallService installService;
@Autowired
private InstallBiz installBiz;
@Autowired
private FabricConfigGen fabricConfigGen;
@Autowired
private ConfigFileGen configFileGen;
@Autowired
private DockerConfigGenImpl dockerConfigGen;
public void ordererExtend(Map<String, String> newOrdererHostConfig, InitConfigEntity configEntity) {
log.info("为新增 orderer 生成证书");
// 生成证书
try {
fabricConfigGen.configTxGen(configEntity);
fabricConfigGen.cryptoGen(configEntity);
configFileGen.createExtendCerts();
} catch (Exception e) {
log.error("为新增的 orderer 节点生成证书异常", e);
e.printStackTrace();
return;
}
log.info("为新增 orderer 生成 docker 相关文件");
// 生成 docker-compose-order-xxxx.yaml start-order.sh 文件
Map<String, String> filePathMap = new HashMap<>(16);
// 按机器IP分组
Map<String, List<String>> orderGroups = dockerConfigGen.groupHostByIp(newOrdererHostConfig);
for (String orderServerIp : orderGroups.keySet()) {
// 每个 IP 一个 docker-compose 文件
try {
String folderName = UUID.randomUUID().toString();
folderName = StringUtils.deleteAny(folderName, "-");
folderName = orderServerIp + "-new-" + folderName;
String filePath = dockerConfigGen.createOrdererYamlFile(configEntity, orderServerIp, orderGroups.get(orderServerIp), "order-" + folderName);
String parentPath = new File(filePath).getParent();
filePathMap.put(orderServerIp, parentPath);
} catch (IOException e) {
e.printStackTrace();
}
}
log.info("将新生成的证书拷贝到主节点安装目录");
fileService.masterCopyCryptoConfig();
fileService.masterCopyConfigtxFile();
// 启动一个 cli 容器
log.info("主节点创建cli容器");
if (!fabricCliService.createCliContainer(modeService.getInstallPath() + "cli", configEntity)) {
log.error("创建cli容器失败");
return;
}
log.info("修改所有其他 orderer 节点配置");
// 修改所有其他 orderer 节点配置并重启
updateOldOrdererContainers(newOrdererHostConfig, configEntity);
// 收集所有节点加入的通道
log.info("获取所有节点加入的通道列表");
Set<String> channelList = new HashSet<>();
try {
channelList.addAll(fabricCliService.getAllChannels(configEntity));
} catch (IOException e) {
log.error("获取节点加入的所有通道异常", e);
e.printStackTrace();
}
log.info("修改网络配置");
// 修改网络配置
log.info("将新加入的 orderer(s) 加入系统通道");
Map<String, String> oldOrdererConfig = updateService.getOldNodeConfigMap(configEntity.getOrdererHostConfig(), newOrdererHostConfig);
for (String newOrdererHost : newOrdererHostConfig.keySet()) {
log.info("扩容orderer-oldOrdererConfig=" + JSON.toJSONString(oldOrdererConfig));
oldOrdererConfig.put(newOrdererHost, newOrdererHostConfig.get(newOrdererHost));
// 先修改系统通道
if (!updateService.updateNetworkConfig(configEntity.getNetwork() + "-sys-channel", configEntity, oldOrdererConfig)) {
log.error(String.format("为系统通道 %s 更新网络配置失败", configEntity.getNetwork() + "-sys-channel"));
return;
}
// 更新业务通道
if (!CollectionUtils.isEmpty(channelList)) {
for (String channelName : channelList) {
log.info(String.format("将新加入的 orderer(s) 加入 %s 通道", channelName));
if (!updateService.updateNetworkConfig(channelName, configEntity, oldOrdererConfig)) {
log.error(String.format("为通道 %s 更新网络配置失败", channelName));
}
}
}
}
log.info("获取最新创世块");
if (!fabricCliService.fetchGenesisBlock(configEntity)) {
log.error("获取创世块发生错误");
}
log.info("注册 orderer 节点角色");
List<String> ports = new ArrayList<>();
for (String ip : orderGroups.keySet()) {
List<String> hostList = orderGroups.get(ip);
for (String host : hostList) {
int index = host.lastIndexOf(":");
ports.add(host.substring(index + 1));
}
this.rolesBiz.addRole(RoleEnum.ORDER, "http://" + ip + ":8080", ip, ports);
}
for (String ip : filePathMap.keySet()) {
String path = filePathMap.get(ip);
String folderName = new File(path).getName();
if (NetUtil.ipIsMine(ip)) {
fileService.copyFiles(RoleEnum.ORDER, ip, folderName, modeService.getInstallPath(), folderName, configEntity, null);
this.rolesBiz.setServerStatus(ip, InstallStatusEnum.DOWNLOADED);
} else {
log.info("为新增 orderer 打包安装包");
String packFilePath = fileService.packExtendNodeFiles(ip, folderName, RoleEnum.ORDER, configEntity);
// 发送到节点启动
log.info("将生成的文件包发送到新增 orderer 节点");
remoteService.pushSlaveInstallPackage(ip, packFilePath, configEntity);
}
}
log.info("启动 orderer 节点");
// 等待节点启动成功
List<ServerEntity> serverList = this.rolesBiz.getRolesMap().get(RoleEnum.ORDER);
for (String ip : filePathMap.keySet()) {
log.info(String.format("发送安装命令到新增 orderer 节点 %s", ip));
String path = filePathMap.get(ip);
String folderName = new File(path).getName();
// 如果主节点也是此角色则先安装
if (NetUtil.ipIsMine(ip)) {
Map<String, String> hosts = environmentService.getRoleNeedSetHost(RoleEnum.ORDER, configEntity);
if (installService.startRole(RoleEnum.ORDER, ports, hosts, folderName)) {
this.rolesBiz.setServerStatus(ip, InstallStatusEnum.SUCCESS);
}
} else {
for (ServerEntity server : serverList) {
if (server.getHost().equalsIgnoreCase(ip)) {
// 发送安装指令给从节点
do {
HttpInstallResponse response = remoteService.sendInstallCommand(server, RoleEnum.ORDER, folderName, configEntity);
if (ResponseCode.SUCCESS.getCode().equals(response.getCode())) {
log.warn(String.format("发送安装指令给 %s 节点安装 orderer 成功", ip));
this.rolesBiz.setServerStatus(ip, InstallStatusEnum.INSTALLING);
break;
}
log.warn(String.format("发送安装指令给 %s 节点安装 orderer 失败,稍后重试...", ip));
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} while (true);
break;
}
}
}
}
log.info("等待所有 orderer 启动成功");
while (serverList.stream().anyMatch(s -> s.getStatus() != InstallStatusEnum.SUCCESS)) {
try {
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
}
}
log.info("将新 orderer(s) 信息加入本地数据库");
// 更新数据库
for (String host : newOrdererHostConfig.keySet()) {
String ip = newOrdererHostConfig.get(host);
int index = ip.lastIndexOf(":");
String port = ip.substring(index + 1);
ip = ip.substring(0, index);
NodeDO nodeDO = new NodeDO();
nodeDO.setOrgMspId(configEntity.getOrgMSPID());
nodeDO.setRole(RoleEnum.ORDER);
nodeDO.setHostName(host);
nodeDO.setIp(ip);
nodeDO.setPort(Integer.parseInt(port));
nodeDO.setStatus(InstallStatusEnum.SUCCESS);
try {
this.checkPointDb.addNodeRecord(nodeDO);
} catch (SQLException e) {
log.error(String.format("添加新 orderer 节点 %s 记录到数据库异常", host), e);
e.printStackTrace();
}
}
}
/**
* 更新原 orderer 节点
*
* @param newOrdererHostConfig
* @param configEntity
*/
private void updateOldOrdererContainers(Map<String, String> newOrdererHostConfig, InitConfigEntity configEntity) {
Map<String, String> newHosts = new HashMap<>(16);
for (String host : newOrdererHostConfig.keySet()) {
String ipPort = newOrdererHostConfig.get(host);
String ip = ipPort.substring(0, ipPort.lastIndexOf(":"));
newHosts.put(host, ip);
}
Map<String, String> needSendIps = new HashMap<>(16);
for (String newHost : newOrdererHostConfig.keySet()) {
for (String curHost : configEntity.getOrdererHostConfig().keySet()) {
String curIp = configEntity.getOrdererHostConfig().get(curHost);
curIp = curIp.substring(0, curIp.lastIndexOf(":"));
if (!curHost.equalsIgnoreCase(newHost)) {
needSendIps.put(curHost, curIp);
}
}
}
// 即使本机也可以发送此命令更新
for (String oldHost : needSendIps.keySet()) {
String ip = needSendIps.get(oldHost);
// 发送更新 orderer 的命令
UpdateCmd cmd = new UpdateCmd();
cmd.setRole(RoleEnum.ORDER);
cmd.setHosts(newHosts);
cmd.setPeerHostConfig(newOrdererHostConfig);
cmd.setCurrentHost(oldHost);
//发送更新host脚本
String updateOrdererHostPath = modeService.getInitDir() + "template" + File.separator + "updateOrdererHost.sh";
if (NetUtil.ipIsMine(ip)) {
String shDesPath = "/var/run/updateOrdererHost.sh";
try {
FileUtils.copyFile(new File(updateOrdererHostPath), new File(shDesPath));
installBiz.updateOrderers(cmd);
} catch (IOException e) {
log.error("复制updateOrdererHost.sh文件发生异常");
e.printStackTrace();
}
} else {
int retryInit = 0;
int retryTotal = 10;
do {
if (retryTotal == retryInit) {
log.error("重试超过次数");
break;
}
String result = this.httpClient.sendFileAndJson("http://" + ip + ":8080/v1/install/update", updateOrdererHostPath, JSONObject.toJSONString(cmd));
if (!StringUtils.isEmpty(result)) {
HttpInstallResponse response = JSONObject.parseObject(result, HttpInstallResponse.class);
if (ResponseCode.SUCCESS.getCode().equalsIgnoreCase(response.getCode())) {
break;
}
}
log.error(String.format("发送更新 orderer 指令到节点 %s 返回错误, 稍后重试", ip));
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
retryInit++;
} while (true);
}
}
}
}

View file

@ -0,0 +1,186 @@
package com.cgb.bcpinstall.biz;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cgb.bcpinstall.common.entity.RemoveCmd;
import com.cgb.bcpinstall.common.entity.RoleEnum;
import com.cgb.bcpinstall.common.entity.init.InitConfigEntity;
import com.cgb.bcpinstall.common.response.HttpInstallResponse;
import com.cgb.bcpinstall.common.response.ResponseCode;
import com.cgb.bcpinstall.common.util.HttpClientUtil;
import com.cgb.bcpinstall.common.util.NetUtil;
import com.cgb.bcpinstall.db.CheckPointDb;
import com.cgb.bcpinstall.db.table.NodeDO;
import com.cgb.bcpinstall.service.FabricCliService;
import com.cgb.bcpinstall.service.FileService;
import com.cgb.bcpinstall.service.ModeService;
import com.cgb.bcpinstall.service.UpdateService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.*;
/**
* @author zheng.li
* @date 2020/2/3 11:04
*/
@Service
@Slf4j
public class OrdererRemoveBiz {
@Autowired
private HttpClientUtil httpClient;
@Autowired
private CheckPointDb checkPointDb;
@Autowired
private ModeService modeService;
@Autowired
private FabricCliService fabricCliService;
@Autowired
private UpdateService updateService;
@Autowired
private FileService fileService;
public void ordererRemove(Map<String, String> removedOrdererHostConfig, InitConfigEntity configEntity) {
log.info("主节点启动 cli 容器");
// 启动一个 cli 容器
if (!fabricCliService.createCliContainer(modeService.getInstallPath() + "cli", configEntity)) {
log.error("创建cli容器失败");
return;
}
// 收集所有节点加入的通道
log.info("获取所有节点加入的通道列表");
Set<String> channelList = new HashSet<>();
try {
channelList.addAll(fabricCliService.getAllChannels(configEntity));
} catch (IOException e) {
log.error("获取节点加入的所有通道异常", e);
e.printStackTrace();
}
log.info("缩容orderer-获取的通道列表:" + JSON.toJSONString(channelList));
log.info("修改网络配置");
Map<String, String> oldOrdererConfig = configEntity.getOrdererHostConfig();
oldOrdererConfig.putAll(removedOrdererHostConfig);
for (String host : removedOrdererHostConfig.keySet()) {
log.info("缩容orderer-oldOrdererConfig=" + JSON.toJSONString(oldOrdererConfig));
oldOrdererConfig.remove(host);
// 修改网络配置
log.info("将移除的 orderer(s) 从系统通道中移除");
// 先修改系统通道
if (!updateService.updateNetworkConfig(configEntity.getNetwork() + "-sys-channel", configEntity, oldOrdererConfig)) {
log.error(String.format("为系统通道 %s 更新网络配置失败", configEntity.getNetwork() + "-sys-channel"));
return;
}
channelList.remove(configEntity.getNetwork() + "-sys-channel");
for (String channelName : channelList) {
log.info(String.format("将移除的 orderer(s) 从通道 %s 中移除", channelName));
if (!updateService.updateNetworkConfig(channelName, configEntity, oldOrdererConfig)) {
log.error(String.format("为通道 %s 更新网络配置失败", channelName));
}
}
}
log.info("移除主节点目录下的证书");
fileService.removeCertFile(RoleEnum.ORDER, configEntity, removedOrdererHostConfig, true);
log.info("移除 orderer(s) 节点");
removeOrdererContainer(removedOrdererHostConfig, configEntity);
log.info("将已移除的 orderer(s) 节点从数据库中删除");
// 从数据库中删除
for (String host : removedOrdererHostConfig.keySet()) {
String ip = removedOrdererHostConfig.get(host);
int index = ip.lastIndexOf(":");
String port = ip.substring(index + 1);
ip = ip.substring(0, index);
NodeDO nodeDO = new NodeDO();
nodeDO.setRole(RoleEnum.ORDER);
nodeDO.setOrgMspId(configEntity.getOrgMSPID());
nodeDO.setHostName(host);
nodeDO.setIp(ip);
nodeDO.setPort(Integer.parseInt(port));
try {
this.checkPointDb.deleteNodeRecord(nodeDO);
} catch (SQLException e) {
log.error(String.format("将节点 %s 从数据库中删除异常", host), e);
e.printStackTrace();
}
}
}
private void removeOrdererContainer(Map<String, String> removedOrdererHostConfig, InitConfigEntity configEntity) {
// 通知节点移除
// 根据IP分组
Map<String, List<String>> groups = new HashMap<>(16);
for (String host : removedOrdererHostConfig.keySet()) {
String ip = removedOrdererHostConfig.get(host);
int index = ip.lastIndexOf(":");
String port = ip.substring(index + 1);
ip = ip.substring(0, index);
List<String> hostList;
if (groups.containsKey(ip)) {
hostList = groups.get(ip);
} else {
hostList = new ArrayList<>();
groups.put(ip, hostList);
}
hostList.add(host + ":" + port);
}
String stopNodeFilePath = modeService.getInitDir() + "template/stopNode.sh";
for (String ip : groups.keySet()) {
RemoveCmd peerRemoveCmd = updateService.createRemoveCmd(ip, groups.get(ip), RoleEnum.ORDER);
peerRemoveCmd.setOrdererDomain(configEntity.getOrdererDomain());
if (NetUtil.ipIsMine(ip)) {
try {
FileUtils.copyFile(new File(stopNodeFilePath), new File(modeService.getInstallPath() + "stopNode.sh"));
} catch (Exception e) {
log.info("复制stopNode.sh发生异常");
return;
}
updateService.removeNode(RoleEnum.ORDER, peerRemoveCmd.getOrdererDomain(), peerRemoveCmd.getHostNames(), peerRemoveCmd.getPorts());
} else {
String stopFilePath = modeService.getInitDir() + "template/stopNode.sh";
String url = "http://" + ip + ":8080/v1/install/remove";
do {
try {
String result = this.httpClient.sendFileAndJson(url, stopFilePath, JSONObject.toJSONString(peerRemoveCmd));
if (!StringUtils.isEmpty(result)) {
HttpInstallResponse response = JSONObject.parseObject(result, HttpInstallResponse.class);
if (ResponseCode.SUCCESS.getCode().equalsIgnoreCase(response.getCode())) {
break;
}
}
log.warn(String.format("给节点 %s 发送移除命令返回失败,稍后重试", ip));
} catch (Exception e) {
log.warn(String.format("给节点 %s 发送移除命令异常,稍后重试", ip), e);
e.printStackTrace();
}
try {
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
}
} while (true);
}
}
}
}

View file

@ -0,0 +1,336 @@
package com.cgb.bcpinstall.biz;
import com.alibaba.fastjson.JSON;
import com.cgb.bcpinstall.common.entity.*;
import com.cgb.bcpinstall.common.entity.init.InitConfigEntity;
import com.cgb.bcpinstall.common.response.HttpInstallResponse;
import com.cgb.bcpinstall.common.response.ResponseCode;
import com.cgb.bcpinstall.common.util.*;
import com.cgb.bcpinstall.config.ConfigFileGen;
import com.cgb.bcpinstall.config.FabricConfigGen;
import com.cgb.bcpinstall.config.configGenImpl.DockerConfigGenImpl;
import com.cgb.bcpinstall.db.CheckPointDb;
import com.cgb.bcpinstall.db.table.NodeDO;
import com.cgb.bcpinstall.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.*;
/**
* @author zheng.li
* @date 2020/2/3 10:03
*/
@Service
@Slf4j
public class PeerExtendBiz {
@Autowired
private RolesBiz rolesBiz;
@Autowired
private CheckPointDb checkPointDb;
@Autowired
private ModeService modeService;
@Autowired
private FileService fileService;
@Autowired
private EnvironmentService environmentService;
@Autowired
private FabricCliService fabricCliService;
@Autowired
private RemoteService remoteService;
@Autowired
private InstallService installService;
@Autowired
private FabricConfigGen fabricConfigGen;
@Autowired
private ConfigFileGen configFileGen;
@Autowired
private DockerConfigGenImpl dockerConfigGen;
public void peerExtend(Map<String, String> diffPeerHostConfig, InitConfigEntity configEntity) {
//在主节点修改crypto-config.yaml文件添加新节点hostname,编写生成证书命令行参数extend执行命令生成新节点证书,生成新增节点的compose文件
//在crypto-config配置文件添加新节点hostName调用generate.sh生成新节点证书
log.info("在crypto-config配置文件添加新节点hostName调用generate.sh生成新节点证书");
/*initializer.reCreateNewPeerConfigFile(configEntity);*/
fabricConfigGen.cryptoGen(configEntity);
configFileGen.createExtendCerts();
//生成新节点的docker-compose文件
log.info("生成新节点的docker-compose文件");
Map<String, List<String>> peerHostGroup = dockerConfigGen.groupHostByIp(diffPeerHostConfig);
Map<String, String> ipPathMap = this.createNewPeerDockerFile(configEntity, peerHostGroup);
//将新生成的证书拷贝到主节点安装目录
log.info("将新生成的证书拷贝到主节点安装目录");
fileService.masterCopyCryptoConfig();
log.info("注册新Peer节点角色");
List<String> ports = this.registerNewPeerRole(peerHostGroup);
log.info("推送新peer的安装文件");
this.sendNewPeerFile(ipPathMap, configEntity);
//启动新节点
log.info("启动新新增peer");
List<ServerEntity> serverList = this.startNewPeer(ipPathMap, ports, configEntity);
log.info("等待所有 peer 启动成功");
while (serverList.stream().anyMatch(s -> s.getStatus() != InstallStatusEnum.SUCCESS)) {
try {
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
}
}
// 将新节点的域名更新到cli所在宿主机的host
// 在宿主机防火墙中打开新节点的端口
log.info("将新节点的域名写入到hosts在防火墙中开启新节点端口");
environmentService.updateNewPeerHostPort(diffPeerHostConfig);
// 启动一个 cli 容器
log.info("主节点创建cli容器");
if (!fabricCliService.createCliContainer(modeService.getInstallPath() + "cli", configEntity)) {
log.error("创建cli容器失败");
return;
}
//获取扩容peer可以加入的业务链列表
Set<String> channelList = new HashSet<>();
try {
channelList.addAll(fabricCliService.getAllChannels(configEntity));
} catch (IOException e) {
e.printStackTrace();
}
//新节点加入链
if (!CollectionUtils.isEmpty(channelList)) {
log.info("新增节点加入链");
Set<String> joinChannels = newPeerJoinChannel(configEntity, diffPeerHostConfig, channelList);
log.info("新增节点加入链-joinChannels=" + JSON.toJSONString(joinChannels));
}
log.info("将新 peer(s) 信息加入本地数据库");
// 更新数据库
for (String host : diffPeerHostConfig.keySet()) {
String ip = diffPeerHostConfig.get(host);
int index = ip.lastIndexOf(":");
String port = ip.substring(index + 1);
ip = ip.substring(0, index);
NodeDO nodeDO = new NodeDO();
nodeDO.setOrgMspId(configEntity.getOrgMSPID());
nodeDO.setRole(RoleEnum.PEER);
nodeDO.setHostName(host);
nodeDO.setIp(ip);
nodeDO.setPort(Integer.parseInt(port));
nodeDO.setStatus(InstallStatusEnum.SUCCESS);
try {
this.checkPointDb.addNodeRecord(nodeDO);
} catch (SQLException e) {
log.error(String.format("添加新 peer 节点 %s 记录到数据库异常", host), e);
e.printStackTrace();
}
}
}
private List<String> registerNewPeerRole(Map<String, List<String>> peerHostGroup) {
List<String> ports = new ArrayList<>();
for (String ip : peerHostGroup.keySet()) {
List<String> hostList = peerHostGroup.get(ip);
for (String host : hostList) {
int index = host.lastIndexOf(":");
ports.add(host.substring(index + 1));
}
this.rolesBiz.addRole(RoleEnum.PEER, "http://" + ip + ":8080", ip, ports);
}
return ports;
}
private void sendNewPeerFile(Map<String, String> ipPathMap, InitConfigEntity configEntity) {
for (String ip : ipPathMap.keySet()) {
String path = ipPathMap.get(ip);
String folderName = new File(path).getName();
if (NetUtil.ipIsMine(ip)) {
fileService.copyFiles(RoleEnum.PEER, ip, folderName, modeService.getInstallPath(), folderName, configEntity, null);
this.rolesBiz.setServerStatus(ip, InstallStatusEnum.DOWNLOADED);
} else {
log.info("为新增 peer 打包安装包");
String packFilePath = fileService.packExtendNodeFiles(ip, folderName, RoleEnum.PEER, configEntity);
// 发送到节点启动
log.info("将生成的文件包发送到新增 peer 节点");
remoteService.pushSlaveInstallPackage(ip, packFilePath, configEntity);
}
}
}
private List<ServerEntity> startNewPeer(Map<String, String> ipPathMap, List<String> ports, InitConfigEntity configEntity) {
List<ServerEntity> serverList = this.rolesBiz.getRolesMap().get(RoleEnum.PEER);
for (String ip : ipPathMap.keySet()) {
log.info(String.format("发送安装命令到新增 peer 节点 %s", ip));
String path = ipPathMap.get(ip);
String folderName = new File(path).getName();
// 如果主节点也是此角色则先安装
if (NetUtil.ipIsMine(ip)) {
Map<String, String> hosts = environmentService.getRoleNeedSetHost(RoleEnum.PEER, configEntity);
if (installService.startRole(RoleEnum.PEER, ports, hosts, folderName)) {
this.rolesBiz.setServerStatus(ip, InstallStatusEnum.SUCCESS);
}
} else {
for (ServerEntity server : serverList) {
if (server.getHost().equalsIgnoreCase(ip)) {
// 发送安装指令给从节点
do {
HttpInstallResponse response = remoteService.sendInstallCommand(server, RoleEnum.PEER, folderName, configEntity);
if (ResponseCode.SUCCESS.getCode().equals(response.getCode())) {
log.warn(String.format("发送安装指令给 %s 节点安装 peer 成功", ip));
this.rolesBiz.setServerStatus(ip, InstallStatusEnum.INSTALLING);
break;
}
log.warn(String.format("发送安装指令给 %s 节点安装 peer 失败,稍后重试...", ip));
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} while (true);
break;
}
}
}
}
return serverList;
}
private Set<String> newPeerJoinChannel(InitConfigEntity configEntity, Map<String, String> diffPeerHostConifg, Set<String> channelList) {
//获取运行脚本所需参数peerAddresspeerTlsRootpeerTlsCert,peerTlsKeyorderer的域名:端口对应orderer的ca证书加入链的名称
String privateChannel = "privatechannel" + configEntity.getOrgMSPID().toLowerCase();
String ordererHost = configEntity.getOrdererHostConfig().keySet().iterator().next();
String ordererPort = configEntity.getOrdererHostConfig().get(ordererHost).split(":")[1];
String orderer = ordererHost + ":" + ordererPort;
String ordererCaPath = String.format("/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/%s/orderers/%s/msp/tlscacerts/tlsca.%s-cert.pem", configEntity.getOrdererDomain(), ordererHost, configEntity.getOrdererDomain());
Set<String> joinChannels = null;
for (String peerHost : diffPeerHostConifg.keySet()) {
//扩容节点选择加入链
joinChannels = this.selectJoinChannel(channelList, privateChannel);
//初始化环境参数
String peerPort = diffPeerHostConifg.get(peerHost).split(":")[1];
String peerAddress = peerHost + ":" + peerPort;
String peerTlsCaPath = String.format("/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/%s/peers/%s/tls/ca.crt", configEntity.getPeerDomain(), peerHost);
String peerTlsCertPath = String.format("/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/%s/peers/%s/tls/server.crt", configEntity.getPeerDomain(), peerHost);
String peerTlsKeyPath = String.format("/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/%s/peers/%s/tls/server.key", configEntity.getPeerDomain(), peerHost);
//初始化执行命令
for (String joinChannel : joinChannels) {
String cmd = String.format("docker exec cli bash ./scripts/newPeerJoinChannel.sh -c %s -o %s -O %s -p %s -r %s -e %s -k %s", joinChannel, orderer, ordererCaPath, peerAddress, peerTlsCaPath, peerTlsCertPath, peerTlsKeyPath);
//执行peer加入链的命令
try {
FileUtils.copyFile(new File(modeService.getInitDir() + "template/newPeerJoinChannel.sh"), new File(modeService.getInstallPath() + "cli/scripts/newPeerJoinChannel.sh"));
ProcessUtil.Result result = ProcessUtil.execCmd(cmd, null, modeService.getInstallPath() + "cli");
} catch (Exception e) {
log.error("执行 docker 脚本异常", e);
e.printStackTrace();
}
}
}
return joinChannels;
}
/**
* 新节点加入所选链
*
* @param queryChannelList
* @param privateChannel
* @return
*/
private Set<String> selectJoinChannel(Set<String> queryChannelList, String privateChannel) {
Set<String> selectChannels = new HashSet<>();
Map<String, String> selectChannelIndexMap = new HashMap<>(16);
//选择需要加入的业务链
System.out.println("请根据以下列表选择扩容peer需要加入的业务链。");
StringBuilder builder = new StringBuilder();
int nextLine = 1;
for (String channel : queryChannelList) {
if (channel.equals(privateChannel) || StringUtils.isEmpty(channel)) {
continue;
}
builder.append(nextLine).append(")").append(channel).append("\t");
selectChannelIndexMap.put(Integer.toString(nextLine), channel);
if (nextLine % 5 == 0) {
builder.append("\n");
}
nextLine += 1;
}
System.out.println(builder.toString());
Scanner sc = new Scanner(System.in);
System.out.print("请输入需要加入的链名编号(多于一个编号时以“,”分割,请回车后输入):");
String inputIndexList = "";
if (sc.hasNextLine()) {
inputIndexList = sc.nextLine();
System.out.println("用户输入" + inputIndexList);
}
sc.close();
if (StringUtils.isEmpty(inputIndexList)) {
log.info("扩容节点——用户输入为空,默认加入本机构的所有业务链");
selectChannels.addAll(queryChannelList);
selectChannels.remove("");
} else {
String[] channelIndexArray = inputIndexList.split(",");
Arrays.stream(channelIndexArray).forEach(i -> {
String channelName = selectChannelIndexMap.get(i);
if (!StringUtils.isEmpty(channelName)) {
selectChannels.add(channelName);
}
});
selectChannels.add(privateChannel);
}
return selectChannels;
}
/**
* 生成新节点的docker文件
*
* @param configEntity
* @param peerHostGroup
* @throws IOException
*/
private Map<String, String> createNewPeerDockerFile(InitConfigEntity configEntity, Map<String, List<String>> peerHostGroup) {
Map<String, String> ipPathMap = new HashMap<>(16);
for (String peerServerIp : peerHostGroup.keySet()) {
try {
String folderName = UUID.randomUUID().toString();
folderName = StringUtils.deleteAny(folderName, "-");
folderName = "new-" + folderName;
String filePath = dockerConfigGen.createPeerYamlFile(configEntity, peerServerIp, peerHostGroup.get(peerServerIp), "fabric-net/dockerFile" + File.separator + "peer-" + folderName + File.separator);
String parentPath = new File(filePath).getParent();
ipPathMap.put(peerServerIp, parentPath);
} catch (IOException e) {
e.printStackTrace();
}
}
return ipPathMap;
}
}

View file

@ -0,0 +1,132 @@
package com.cgb.bcpinstall.biz;
import com.alibaba.fastjson.JSONObject;
import com.cgb.bcpinstall.common.entity.RemoveCmd;
import com.cgb.bcpinstall.common.entity.RoleEnum;
import com.cgb.bcpinstall.common.entity.init.InitConfigEntity;
import com.cgb.bcpinstall.common.response.HttpInstallResponse;
import com.cgb.bcpinstall.common.response.ResponseCode;
import com.cgb.bcpinstall.common.util.HttpClientUtil;
import com.cgb.bcpinstall.common.util.NetUtil;
import com.cgb.bcpinstall.config.ConfigFileGen;
import com.cgb.bcpinstall.config.GlobalConfig;
import com.cgb.bcpinstall.config.configGenImpl.DockerConfigGenImpl;
import com.cgb.bcpinstall.db.CheckPointDb;
import com.cgb.bcpinstall.db.table.NodeDO;
import com.cgb.bcpinstall.service.FileService;
import com.cgb.bcpinstall.service.ModeService;
import com.cgb.bcpinstall.service.UpdateService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.io.File;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
/**
* @author zheng.li
* @date 2020/2/3 10:03
*/
@Service
@Slf4j
public class PeerRemoveBiz {
@Autowired
private HttpClientUtil httpClient;
@Autowired
private CheckPointDb checkPointDb;
@Autowired
private ModeService modeService;
@Autowired
private UpdateService updateService;
@Autowired
private FileService fileService;
@Autowired
private DockerConfigGenImpl dockerConfigGen;
@Value("${init.dir}")
private String initDir;
public void peerRemove(Map<String, String> removedPeerHostConfig, InitConfigEntity configEntity) {
// 通知移除的 peer 节点停止并删除相关文件
log.info("移除节点停止peer容器");
Map<String, List<String>> removeGroup = dockerConfigGen.groupHostByIp(removedPeerHostConfig);
String stopNodeFilePath = (this.initDir.endsWith(File.separator) ? this.initDir : this.initDir + File.separator) + "template/stopNode.sh";
for (String ip : removeGroup.keySet()) {
RemoveCmd peerRemoveCmd = updateService.createRemoveCmd(ip, removeGroup.get(ip), RoleEnum.PEER);
peerRemoveCmd.setPeerDomain(configEntity.getPeerDomain());
if (NetUtil.ipIsMine(ip)) {
try {
FileUtils.copyFile(new File(stopNodeFilePath), new File(modeService.getInstallPath() + "stopNode.sh"));
} catch (Exception e) {
log.info("复制stopNode.sh发生异常");
return;
}
updateService.removeNode(RoleEnum.PEER, peerRemoveCmd.getPeerDomain(), peerRemoveCmd.getHostNames(), peerRemoveCmd.getPorts());
} else {
String url = "http://" + ip + ":8080/v1/install/remove";
do {
try {
String result = this.httpClient.sendFileAndJson(url, stopNodeFilePath, JSONObject.toJSONString(peerRemoveCmd));
if (!StringUtils.isEmpty(result)) {
HttpInstallResponse response = JSONObject.parseObject(result, HttpInstallResponse.class);
if (ResponseCode.SUCCESS.getCode().equalsIgnoreCase(response.getCode())) {
break;
}
}
log.warn(String.format("给节点 %s 发送移除命令返回失败,稍后重试", ip));
} catch (Exception e) {
log.warn(String.format("给节点 %s 发送移除命令异常,稍后重试", ip), e);
e.printStackTrace();
}
try {
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
}
} while (true);
}
}
//将主节点相关证书删除
log.info("将主节点相关证书删除");
fileService.removeCertFile(RoleEnum.PEER, configEntity, removedPeerHostConfig, true);
// 更新本地数据库
log.info("将已移除的 peer(s) 节点从数据库中删除");
// 从数据库中删除
for (String host : removedPeerHostConfig.keySet()) {
String ip = removedPeerHostConfig.get(host);
int index = ip.lastIndexOf(":");
String port = ip.substring(index + 1);
ip = ip.substring(0, index);
NodeDO nodeDO = new NodeDO();
nodeDO.setRole(RoleEnum.PEER);
nodeDO.setOrgMspId(configEntity.getOrgMSPID());
nodeDO.setHostName(host);
nodeDO.setIp(ip);
nodeDO.setPort(Integer.parseInt(port));
try {
this.checkPointDb.deleteNodeRecord(nodeDO);
} catch (SQLException e) {
log.error(String.format("将节点 %s 从数据库中删除异常", host), e);
e.printStackTrace();
}
}
}
}

View file

@ -0,0 +1,81 @@
package com.cgb.bcpinstall.biz;
import com.cgb.bcpinstall.common.entity.InstallResult;
import com.cgb.bcpinstall.common.entity.InstallStatusEnum;
import com.cgb.bcpinstall.common.entity.RoleEnum;
import com.cgb.bcpinstall.common.entity.ServerEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@Service
public class RolesBiz {
// 角色对机器URL的map
private Map<RoleEnum, List<ServerEntity>> rolesMap = new HashMap<>();
synchronized public void addRole(RoleEnum role, String httpUrl, String roleIp, List<String> rolePorts) {
List<ServerEntity> servers;
if (this.rolesMap.containsKey(role)) {
servers = this.rolesMap.get(role);
} else {
servers = new ArrayList<>();
this.rolesMap.put(role, servers);
}
if (servers.stream().noneMatch(s -> s.getHost().equalsIgnoreCase(roleIp))) {
ServerEntity serverEntity = new ServerEntity();
serverEntity.setRole(role);
serverEntity.setHttpUrl(httpUrl);
serverEntity.setHost(roleIp);
serverEntity.setRolePorts(rolePorts);
serverEntity.setStatus(InstallStatusEnum.REGISTERED);
servers.add(serverEntity);
}
}
public List<RoleEnum> getRole(String roleIp) {
List<RoleEnum> roleList = new ArrayList<>();
for (RoleEnum roleEnum: this.rolesMap.keySet()) {
if (this.rolesMap.get(roleEnum).stream().anyMatch(s -> s.getHost().equals(roleIp))) {
roleList.add(roleEnum);
}
}
return roleList;
}
synchronized public void setServerStatus(String remoteAddress, InstallStatusEnum status) {
this.rolesMap.values().forEach(c -> c.forEach(s -> {
if (s.getHost().equals(remoteAddress)) {
s.setStatus(status);
}
}));
}
public Map<RoleEnum, List<ServerEntity>> getRolesMap() {
return this.rolesMap;
}
synchronized public void updateInstallResult(String remoteAddress, InstallResult result) {
for (RoleEnum role: this.rolesMap.keySet()) {
if (role == result.getRole()) {
List<ServerEntity> serverEntities = this.rolesMap.get(role);
for (ServerEntity server: serverEntities) {
if (server.getHost().endsWith(remoteAddress)) {
server.setStatus(result.isSuccess() ? InstallStatusEnum.SUCCESS : InstallStatusEnum.FAILED);
}
}
break;
}
}
}
}

View file

@ -0,0 +1,172 @@
package com.cgb.bcpinstall.biz;
import com.cgb.bcpinstall.common.entity.*;
import com.cgb.bcpinstall.common.entity.init.InitConfigEntity;
import com.cgb.bcpinstall.db.CheckPointDb;
import com.cgb.bcpinstall.db.table.NodeDO;
import com.cgb.bcpinstall.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.sql.SQLException;
import java.util.*;
/**
* @author zheng.li
* @date 2020/2/2 14:01
*/
@Service
@Slf4j
public class UpdateNetworkBiz implements InstallMode {
@Autowired
private CheckPointDb checkPointDb;
@Autowired
private OrdererExtendBiz ordererExtendBiz;
@Autowired
private OrdererRemoveBiz ordererRemoveBiz;
@Autowired
private PeerRemoveBiz peerRemoveBiz;
@Autowired
private PeerExtendBiz peerExtendBiz;
@Autowired
private RemoteService remoteService;
@Override
public void run(InitConfigEntity configEntity) {
DiffHostConfigs removedNodeConfigs = getRemovedNodes(configEntity);
DiffHostConfigs addedNodeConfigs = getAddedNodes(configEntity);
if (removedNodeConfigs == null && addedNodeConfigs == null
|| (CollectionUtils.isEmpty(removedNodeConfigs.getOrdererHostConfig())
&& CollectionUtils.isEmpty(removedNodeConfigs.getPeerHostConfig())
&& CollectionUtils.isEmpty(addedNodeConfigs.getOrdererHostConfig())
&& CollectionUtils.isEmpty(addedNodeConfigs.getPeerHostConfig()))) {
log.info("未发现与上次安装的差异,无需安装任何节点");
return;
}
doRemoveNodes(removedNodeConfigs, configEntity);
doNewNodesInstall(addedNodeConfigs, configEntity);
// 通知结束
Set<String> serverUrls = new HashSet<>();
parseServerUrl(serverUrls, removedNodeConfigs.getOrdererHostConfig());
parseServerUrl(serverUrls, removedNodeConfigs.getPeerHostConfig());
parseServerUrl(serverUrls, addedNodeConfigs.getOrdererHostConfig());
parseServerUrl(serverUrls, addedNodeConfigs.getPeerHostConfig());
remoteService.notifyNodesToEnd(serverUrls);
}
/**
* 根据配置文件与数据库数据对比获取移除节点信息
*
* @param configEntity
* @return
*/
private DiffHostConfigs getRemovedNodes(InitConfigEntity configEntity) {
DiffHostConfigs removedNodes = new DiffHostConfigs();
// 数据库中搜索所有 orderer 节点
List<NodeDO> nodes = queryNodes(configEntity.getOrgMSPID(), RoleEnum.ORDER);
removedNodes.setOrdererHostConfig(checkRemovedNodes(nodes, configEntity.getOrdererHostConfig()));
nodes = queryNodes(configEntity.getOrgMSPID(), RoleEnum.PEER);
removedNodes.setPeerHostConfig(checkRemovedNodes(nodes, configEntity.getPeerHostConfig()));
return removedNodes;
}
private Map<String, String> checkRemovedNodes(List<NodeDO> prevNodes, Map<String, String> newHostConfig) {
Map<String, String> removedHostConfig = new HashMap<>();
for (NodeDO node : prevNodes) {
if (!newHostConfig.containsKey(node.getHostName())) {
removedHostConfig.put(node.getHostName(), node.getIp() + ":" + node.getPort());
}
}
return removedHostConfig;
}
/**
* 根据配置文件与数据库数据对比获取添加节点信息
*
* @param configEntity
* @return
*/
private DiffHostConfigs getAddedNodes(InitConfigEntity configEntity) {
DiffHostConfigs addedNodes = new DiffHostConfigs();
List<NodeDO> nodes = queryNodes(configEntity.getOrgMSPID(), RoleEnum.ORDER);
addedNodes.setOrdererHostConfig(checkAddedNodes(nodes, configEntity.getOrdererHostConfig()));
nodes = queryNodes(configEntity.getOrgMSPID(), RoleEnum.PEER);
addedNodes.setPeerHostConfig(checkAddedNodes(nodes, configEntity.getPeerHostConfig()));
return addedNodes;
}
private Map<String, String> checkAddedNodes(List<NodeDO> prevNodes, Map<String, String> newHostConfig) {
Map<String, String> addedHostConfig = new HashMap<>();
for (String hostName : newHostConfig.keySet()) {
if (prevNodes.stream().noneMatch(n -> n.getHostName().equalsIgnoreCase(hostName))) {
addedHostConfig.put(hostName, newHostConfig.get(hostName));
}
}
return addedHostConfig;
}
private void doRemoveNodes(DiffHostConfigs removedNodeConfigs, InitConfigEntity configEntity) {
// Orderer
if (!CollectionUtils.isEmpty(removedNodeConfigs.getOrdererHostConfig())) {
ordererRemoveBiz.ordererRemove(removedNodeConfigs.getOrdererHostConfig(), configEntity);
}
// peer
if (!CollectionUtils.isEmpty(removedNodeConfigs.getPeerHostConfig())) {
peerRemoveBiz.peerRemove(removedNodeConfigs.getPeerHostConfig(), configEntity);
}
}
private void doNewNodesInstall(DiffHostConfigs addedNodeConfigs, InitConfigEntity configEntity) {
if (!CollectionUtils.isEmpty(addedNodeConfigs.getOrdererHostConfig())) {
ordererExtendBiz.ordererExtend(addedNodeConfigs.getOrdererHostConfig(), configEntity);
}
if (!CollectionUtils.isEmpty(addedNodeConfigs.getPeerHostConfig())) {
peerExtendBiz.peerExtend(addedNodeConfigs.getPeerHostConfig(), configEntity);
}
}
private void parseServerUrl(Set<String> serverUrls, Map<String, String> hostConfig) {
if (CollectionUtils.isEmpty(hostConfig)) {
return;
}
for (String host : hostConfig.keySet()) {
String ip = hostConfig.get(host);
ip = ip.substring(0, ip.lastIndexOf(":"));
serverUrls.add("http://" + ip + ":8080/");
}
}
private List<NodeDO> queryNodes(String orgMspID, RoleEnum role) {
NodeDO nodeDO = new NodeDO();
nodeDO.setOrgMspId(orgMspID);
nodeDO.setRole(role);
try {
return this.checkPointDb.find(nodeDO);
} catch (SQLException e) {
log.error("查询数据库异常", e);
e.printStackTrace();
}
return null;
}
}

View file

@ -0,0 +1,14 @@
package com.cgb.bcpinstall.biz.helper;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.nodes.Tag;
import org.yaml.snakeyaml.representer.Representer;
public class YamlRepresenter extends Representer {
public YamlRepresenter(DumperOptions options) {
super(options);
this.nullRepresenter = data -> representScalar(Tag.NULL, "");
}
}

View file

@ -0,0 +1,104 @@
package com.cgb.bcpinstall.config;
import com.cgb.bcpinstall.common.entity.init.InitConfigEntity;
import com.cgb.bcpinstall.common.util.CacheUtil;
import com.cgb.bcpinstall.common.util.ProcessUtil;
import com.cgb.bcpinstall.service.ModeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author zheng.li
* @date 2020/3/12 15:04
*/
@Component
@Slf4j
public class ConfigFileGen {
@Autowired
private ModeService modeService;
@Autowired
private DockerConfigGen dockerConfigGen;
@Autowired
private FabricConfigGen fabricConfigGen;
public void createConfigFile(InitConfigEntity config) {
// 生成 configtx.yaml 文件,其它机构在profile中只有PrivateChannel配置需在子类具体实现
if (fabricConfigGen.configTxGen(config)) {
log.info("生成 configtx.yaml 文件成功");
} else {
log.error("生成 configtx.yaml 文件失败");
}
// 生成 crypto-config.yaml 文件
if (fabricConfigGen.cryptoGen(config)) {
log.info("生成 crypto-config.yaml 文件成功");
} else {
log.error("生成 crypto-config.yaml 文件失败");
}
// 创建 crypto-config 目录和证书
if (createNewCerts()) {
log.info("创建证书成功");
} else {
log.error("创建证书失败");
}
// 生成 orderer docker compose yaml 文件
if (dockerConfigGen.ordererComposeFileGen(config)) {
log.info("生成 docker-compose-orderer.yaml 文件成功");
} else {
log.error("生成 docker-compose-orderer.yaml 文件失败");
}
// 生成 peer docker compose yaml 文件,本配置文件不区分发起机构与其他机构可具体实现
if (dockerConfigGen.peerComposeFileGen(config)) {
log.info("生成 docker-compose-peer.yaml 文件成功");
} else {
log.error("生成 docker-compose-peer.yaml 文件失败");
}
}
/**
* 根据crypto-config生成新证书文件
*
* @return
*/
public boolean createNewCerts() {
return createCerts("up");
}
/**
* 根据crypto-config在已存在证书基础下生成新节点证书文件
*
* @return
*/
public boolean createExtendCerts() {
return createCerts("extend");
}
/**
* 根据mode生成证书
*
* @param mode
* @return
*/
private boolean createCerts(String mode) {
String workingDir = modeService.getInitDir() + "fabric-net/cryptoAndConfig";
String shellFilePath = modeService.getInitDir() + "generate.sh";
try {
ProcessUtil.Result result = ProcessUtil.execCmd("bash " + shellFilePath + " " + mode, new String[]{"CRYPTTOGEN_FILE_PATH" + "=" + CacheUtil.getCryptogenFilePath()}, workingDir);
if (result.getCode() == 0) {
return true;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}

View file

@ -0,0 +1,25 @@
package com.cgb.bcpinstall.config;
import com.cgb.bcpinstall.common.entity.init.InitConfigEntity;
/**
* @author zheng.li
* @date 2020/3/12 15:07
*/
public interface DockerConfigGen {
/**
* 生成peer的docker-compose文件
*
* @param initConfig 配置信息
* @return true--生成成功 false--生成失败
*/
boolean peerComposeFileGen(InitConfigEntity initConfig);
/**
* 生成orderer的docker-compose文件
*
* @param initConfig 配置信息
* @return true--生成成功 false--生成失败
*/
boolean ordererComposeFileGen(InitConfigEntity initConfig);
}

View file

@ -0,0 +1,25 @@
package com.cgb.bcpinstall.config;
import com.cgb.bcpinstall.common.entity.init.InitConfigEntity;
/**
* @author zheng.li
* @date 2020/3/12 15:07
*/
public interface FabricConfigGen {
/**
* 生成configtx.yaml文件
*
* @param initConfig 配置信息
* @return true--生成成功 false--生成失败
*/
boolean configTxGen(InitConfigEntity initConfig);
/**
* 生成crypto-config.yaml文件
*
* @param initConfig 配置信息
* @return true--生成成功 false--生成失败
*/
boolean cryptoGen(InitConfigEntity initConfig);
}

View file

@ -0,0 +1,17 @@
package com.cgb.bcpinstall.config;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Getter
@Setter
@Component
@ConfigurationProperties(prefix = "global")
public class GlobalConfig {
/**
* 是否主节点
*/
private int master;
}

View file

@ -0,0 +1,473 @@
package com.cgb.bcpinstall.config.configGenImpl;
import com.cgb.bcpinstall.common.entity.init.InitConfigEntity;
import com.cgb.bcpinstall.common.util.FileUtil;
import com.cgb.bcpinstall.common.util.NetUtil;
import com.cgb.bcpinstall.config.DockerConfigGen;
import com.cgb.bcpinstall.service.ModeService;
import com.cgb.bcpinstall.service.YamlFileService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author zheng.li
* @date 2020/3/12 15:47
*/
@Service
@Slf4j
public class DockerConfigGenImpl implements DockerConfigGen {
@Autowired
private ModeService modeService;
@Autowired
private YamlFileService yamlFileService;
@Override
public boolean peerComposeFileGen(InitConfigEntity initConfig) {
// 根据 IP 地址分组
Map<String, List<String>> peerGroups = this.groupHostByIp(initConfig.getPeerHostConfig());
// 每个 IP 一个 docker-compose 文件
for (String serverIp : peerGroups.keySet()) {
String path = String.format("fabric-net/dockerFile/peer-%s/", serverIp);
String filePath = null;
try {
filePath = createPeerYamlFile(initConfig, serverIp, peerGroups.get(serverIp), path);
} catch (IOException e) {
e.printStackTrace();
}
if (StringUtils.isEmpty(filePath)) {
return false;
}
}
return true;
}
@Override
public boolean ordererComposeFileGen(InitConfigEntity initConfig) {
// 根据 IP 地址分组
Map<String, List<String>> orderGroups = this.groupHostByIp(initConfig.getOrdererHostConfig());
// 每个 IP 一个 docker-compose 文件
for (String orderServerIp : orderGroups.keySet()) {
String filePath = null;
try {
filePath = createOrdererYamlFile(initConfig, orderServerIp, orderGroups.get(orderServerIp), null);
} catch (IOException e) {
e.printStackTrace();
}
if (StringUtils.isEmpty(filePath)) {
return false;
}
}
return true;
}
/**
* 根据ip进行host分组相同ip的host属于同一集合
*
* @param nodeHostConfig
* @return
*/
public Map<String, List<String>> groupHostByIp(Map<String, String> nodeHostConfig) {
Map<String, List<String>> groups = new HashMap<>(16);
for (String url : nodeHostConfig.keySet()) {
String ip = nodeHostConfig.get(url);
int index = ip.lastIndexOf(":");
String port = ip.substring(index + 1);
ip = ip.substring(0, index);
List<String> nodes;
if (groups.containsKey(ip)) {
nodes = groups.get(ip);
} else {
nodes = new ArrayList<>();
groups.put(ip, nodes);
}
nodes.add(url + ":" + port);
}
return groups;
}
/**
* 根据模板生成orderer的docker-compose文件
*
* @param initConfig 配置信息
* @param hostIp orderer所在主节的ip
* @param orderHosts orderer的host集合
* @param folderName 配置文件生成路径
* @return
* @throws IOException
*/
public String createOrdererYamlFile(InitConfigEntity initConfig, String hostIp, List<String> orderHosts, String folderName) throws IOException {
String workingDir = modeService.getInitDir();
Map<Object, Object> ordererComposeConfig = yamlFileService.loadYamlFile(workingDir + "/template/docker-compose-orderer.yaml");
Map<Object, Object> networks = (Map<Object, Object>) ordererComposeConfig.get("networks");
networks.clear();
for (int i = 0; i < orderHosts.size(); ++i) {
networks.put(initConfig.getNetwork() + i, null);
}
Map<Object, Object> valumes = (Map<Object, Object>) ordererComposeConfig.get("volumes");
valumes.clear();
for (String orderHost : orderHosts) {
valumes.put(orderHost.substring(0, orderHost.lastIndexOf(":")), null);
}
Map<Object, Object> services = (Map<Object, Object>) ordererComposeConfig.get("services");
services.clear();
for (int hostIndex = 0; hostIndex < orderHosts.size(); ++hostIndex) {
String orderHost = orderHosts.get(hostIndex);
int index = orderHost.lastIndexOf(":");
String port = orderHost.substring(index + 1);
orderHost = orderHost.substring(0, index);
Map<Object, Object> orderConfig = yamlFileService.loadYamlFile(workingDir + "template/orderer.yaml");
Map<Object, Object> config = (Map<Object, Object>) orderConfig.get("orderer.example.com");
config.put("container_name", orderHost);
int finalHostIndex = hostIndex;
config.put("networks", new ArrayList<String>() {{
add(initConfig.getNetwork() + finalHostIndex);
}});
List<String> newVols = new ArrayList<>();
List<String> vols = (List<String>) config.get("volumes");
for (String item : vols) {
String newItem;
if (item.contains("orderer.example.com")) {
newItem = item.replace("orderer.example.com", orderHost);
} else {
newItem = item;
}
if (newItem.contains("example.com")) {
int i = orderHost.indexOf(".");
newItem = newItem.replace("example.com", orderHost.substring(i + 1));
}
newVols.add(newItem);
}
newVols.add("/var/run/:/opt/gopath/src/github.com/hyperledger/fabric");
config.put("volumes", newVols);
// extra_hosts
List<String> extraHosts = new ArrayList<>();
for (String eHost : initConfig.getOrdererHostConfig().keySet()) {
if (eHost.equalsIgnoreCase(orderHost)) {
continue;
}
String eIp = initConfig.getOrdererHostConfig().get(eHost);
eIp = eIp.substring(0, eIp.lastIndexOf(":"));
if (eIp.equalsIgnoreCase("127.0.0.1")) {
eIp = NetUtil.getMyNormalIP();
}
extraHosts.add(eHost + ":" + eIp);
}
if (!CollectionUtils.isEmpty(extraHosts)) {
config.put("extra_hosts", extraHosts);
}
List<String> ports = (List<String>) config.get("ports");
ports.clear();
ports.add(port + ":7050");
services.put(orderHost, config);
}
String filePath = workingDir + String.format("fabric-net/dockerFile/%s/", StringUtils.isEmpty(folderName) ? "order-" + hostIp : folderName);
FileUtil.makeFilePath(filePath, false);
String yamlFilePath = filePath + "docker-compose-orderer.yaml";
if (!yamlFileService.writeObjectToYamlFile(ordererComposeConfig, yamlFilePath)) {
return null;
}
// 复制 start-orderer.sh
/*String content = getFileContent(workingDir + "template/start-peer.sh");
String newFilePath = filePath + "start-orderer.sh";
if (!writeFileContent(newFilePath, content)) {
return null;
}*/
String srcShFilePath = workingDir + "template/start-peer.sh";
String newShFilePath = filePath + "start-orderer.sh";
FileUtils.copyFile(new File(srcShFilePath), new File(newShFilePath));
return yamlFilePath;
}
/**
* 根据模板生成peer的docker-compose文件
*
* @param initConfig 配置信息
* @param hostIp orderer所在主节的ip
* @param peerHosts orderer的host集合
* @param folderName 配置文件生成路径
* @return
* @throws IOException
*/
public String createPeerYamlFile(InitConfigEntity initConfig, String hostIp, List<String> peerHosts, String folderName) throws IOException {
Map<Object, Object> peerComposeConfig = yamlFileService.loadYamlFile(modeService.getInitDir() + "template/docker-compose-peer.yaml");
Map<Object, Object> networks = (Map<Object, Object>) peerComposeConfig.get("networks");
networks.clear();
networks.put(initConfig.getNetwork(), null);
Map<Object, Object> valumes = (Map<Object, Object>) peerComposeConfig.get("volumes");
valumes.clear();
for (String host : peerHosts) {
valumes.put(host.substring(0, host.lastIndexOf(":")), null);
}
Map<Object, Object> services = (Map<Object, Object>) peerComposeConfig.get("services");
Map<Object, Object> cliConfig = (Map<Object, Object>) services.get("cli");
services.clear();
List<String> dependsOn = (List<String>) cliConfig.get("depends_on");
dependsOn.clear();
// 获取其他 peer 配置
Map<String, String> othPeerHostConfig = new HashMap<>();
Set<String> peerHostSet = new HashSet<>(peerHosts);
for (String host : initConfig.getPeerHostConfig().keySet()) {
String origIp = initConfig.getPeerHostConfig().get(host);
String ip = origIp.split(":")[0];
String port = origIp.split(":")[1];
if (!ip.equalsIgnoreCase(hostIp)) {
othPeerHostConfig.put(host, origIp);
} else {
host = host + ":" + port;
peerHostSet.add(host);
}
}
// peer
/*int couchDbPort = 7984;*/
/*int ssPort = 9443;*/
String firstHost = null;
for (String peerHost : peerHosts) {
if (StringUtils.isEmpty(firstHost)) {
firstHost = peerHost;
}
String finalPeerHost = peerHost;
List<String> otherPeerHosts = peerHostSet.stream().filter(i -> !i.equals(finalPeerHost)).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(otherPeerHosts)) {
for (String otherHost : otherPeerHosts) {
String host = otherHost.split(":")[0];
log.info("扩容节点其他节点的host:" + host);
String origIp = initConfig.getPeerHostConfig().get(host);
if (origIp.contains("127.0.0.1")) {
origIp = NetUtil.getMyNormalIP() + ":" + origIp.split(":")[1];
}
othPeerHostConfig.put(host, origIp);
}
}
String peerHostPreFix = peerHost.split(initConfig.getPeerDomain())[0];
// couchdb
Map<Object, Object> couchDbConfig = new HashMap<>();
couchDbConfig.put("container_name", peerHostPreFix + initConfig.getOrgMSPID() + "." + "couchdb");
couchDbConfig.put("image", "hyperledger/fabric-couchdb");
couchDbConfig.put("environment", new ArrayList<String>() {{
add("COUCHDB_USER=");
add("COUCHDB_PASSWORD=");
}});
String origHost = peerHost;
int index = peerHost.lastIndexOf(":");
int port = Integer.parseInt(peerHost.substring(index + 1));
peerHost = peerHost.substring(0, index);
String finalCouchdbPeerHost = peerHost;
couchDbConfig.put("ports", new ArrayList<String>() {{
add(initConfig.getCouchdbPortConfig().get(finalCouchdbPeerHost) + ":5984");
}});
couchDbConfig.put("networks", new ArrayList<String>() {{
add(initConfig.getNetwork());
}});
services.put(peerHostPreFix + initConfig.getOrgMSPID() + "." + "couchdb", couchDbConfig);
//
Map<Object, Object> peerConfig = yamlFileService.loadYamlFile(modeService.getInitDir() + "template/peer.yaml");
Map<Object, Object> config = (Map<Object, Object>) peerConfig.get("peer0.org1.example.com");
config.put("container_name", peerHost);
config.put("networks", new ArrayList<String>() {{
add(initConfig.getNetwork());
}});
List<String> newVols = new ArrayList<>();
List<String> vols = (List<String>) config.get("volumes");
for (String item : vols) {
String newItem;
if (item.contains("peer0.org1.example.com")) {
newItem = item.replace("peer0.org1.example.com", peerHost);
} else {
newItem = item;
}
if (newItem.contains("org1.example.com")) {
int i = peerHost.indexOf(".");
newItem = newItem.replace("org1.example.com", peerHost.substring(i + 1));
}
newVols.add(newItem);
}
config.put("volumes", newVols);
// environment
List<String> environment = new ArrayList<>();
environment.add("CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock");
String netWorkConfig;
if (folderName.contains("new")) {
String peerPathSplit = folderName.split("peer-")[1];
String peerNetSplit = peerPathSplit.split(File.separator)[0];
netWorkConfig = "peer-" + peerNetSplit + "_" + initConfig.getNetwork();
} else {
netWorkConfig = "peer_" + initConfig.getNetwork();
}
environment.add("CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=" + netWorkConfig);
environment.add("FABRIC_LOGGING_SPEC=INFO");
environment.add("CORE_PEER_TLS_ENABLED=true");
environment.add("CORE_PEER_GOSSIP_USELEADERELECTION=true");
environment.add("CORE_PEER_GOSSIP_ORGLEADER=false");
environment.add("CORE_PEER_PROFILE_ENABLED=true");
environment.add("CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt");
environment.add("CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key");
environment.add("CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt");
environment.add("CORE_PEER_ID=" + peerHost);
environment.add("CORE_PEER_ADDRESS=" + peerHost + ":" + port);
environment.add("CORE_PEER_LISTENADDRESS=0.0.0.0:" + port);
environment.add("CORE_PEER_CHAINCODEADDRESS=" + peerHost + ":" + (port + 1));
environment.add("CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:" + (port + 1));
if (CollectionUtils.isEmpty(othPeerHostConfig)) {
environment.add("CORE_PEER_GOSSIP_BOOTSTRAP=" + origHost);
} else {
String firstKey = othPeerHostConfig.keySet().iterator().next();
String othIp = othPeerHostConfig.get(firstKey);
environment.add("CORE_PEER_GOSSIP_BOOTSTRAP=" + firstKey + ":" + othIp.substring(othIp.lastIndexOf(":") + 1));
}
environment.add("CORE_PEER_GOSSIP_EXTERNALENDPOINT=" + origHost);
environment.add("CORE_PEER_LOCALMSPID=" + initConfig.getOrgMSPID());
environment.add("CORE_OPERATIONS_LISTENADDRESS=0.0.0.0" + ":9443");
environment.add("CORE_METRICS_PROVIDER=prometheus");
environment.add("CORE_LEDGER_STATE_STATEDATABASE=CouchDB");
environment.add("CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=" + peerHostPreFix + initConfig.getOrgMSPID() + "." + "couchdb" + ":5984");
/*environment.add("CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb" + hIndex + ":" + finalCouchDbPort);*/
environment.add("CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=");
environment.add("CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=");
config.put("environment", environment);
// depends_on
config.put("depends_on", new ArrayList<String>() {{
add(peerHostPreFix + initConfig.getOrgMSPID() + "." + "couchdb");
}});
List<String> extraHosts = new ArrayList<>();
for (String host : initConfig.getOrdererHostConfig().keySet()) {
String ip = initConfig.getOrdererHostConfig().get(host);
int i = ip.lastIndexOf(":");
ip = ip.substring(0, i);
if ("127.0.0.1".equalsIgnoreCase(ip)) {
ip = NetUtil.getMyNormalIP();
}
extraHosts.add(host + ":" + ip);
}
if (!CollectionUtils.isEmpty(othPeerHostConfig)) {
for (String othHost : othPeerHostConfig.keySet()) {
String othIp = othPeerHostConfig.get(othHost);
int i = othIp.lastIndexOf(":");
othIp = othIp.substring(0, i);
if ("127.0.0.1".equals(othIp)) {
othIp = NetUtil.getMyNormalIP();
}
if (!peerHost.contains(othHost)) {
extraHosts.add(othHost + ":" + othIp);
}
}
}
// extraHosts.add("couchdb" + hIndex + ":" + hostIp);
if (!CollectionUtils.isEmpty(extraHosts)) {
config.put("extra_hosts", extraHosts);
}
List<String> ports = (List<String>) config.get("ports");
ports.clear();
ports.add(port + ":" + port);
String metricsPort = initConfig.getMetricPortConfig().get(peerHost);
ports.add(metricsPort + ":" + "9443");
services.put(peerHost, config);
dependsOn.add(peerHost);
}
int index = firstHost.lastIndexOf(":");
String onlyHost = firstHost.substring(0, index);
String orgUrl = initConfig.getPeerDomain();
List<String> newEnvironment = new ArrayList<>();
List<String> environment = (List<String>) cliConfig.get("environment");
for (String oldEnv : environment) {
String newEnv;
if (oldEnv.contains("CORE_PEER_ADDRESS")) {
newEnv = "CORE_PEER_ADDRESS=" + firstHost;
} else if (oldEnv.contains("CORE_PEER_LOCALMSPID")) {
newEnv = "CORE_PEER_LOCALMSPID=" + initConfig.getOrgMSPID();
} else if (oldEnv.contains("CORE_PEER_TLS_CERT_FILE")) {
newEnv = String.format(oldEnv, orgUrl, onlyHost);
} else if (oldEnv.contains("CORE_PEER_TLS_KEY_FILE")) {
newEnv = String.format(oldEnv, orgUrl, onlyHost);
} else if (oldEnv.contains("CORE_PEER_TLS_ROOTCERT_FILE")) {
newEnv = String.format(oldEnv, orgUrl, onlyHost);
} else if (oldEnv.contains("CORE_PEER_MSPCONFIGPATH")) {
newEnv = String.format(oldEnv, orgUrl, orgUrl);
} else {
newEnv = oldEnv;
}
newEnvironment.add(newEnv);
}
cliConfig.put("environment", newEnvironment);
cliConfig.put("networks", new ArrayList<String>() {{
add(initConfig.getNetwork());
}});
cliConfig.remove("extra_hosts");
services.put("cli", cliConfig);
/*String filePath = workingDir + String.format("fabric-net/dockerFile/peer-%s/", hostIp);*/
String filePath = modeService.getInitDir() + folderName;
FileUtil.makeFilePath(filePath, false);
String yamlFilePath = filePath + "docker-compose-peer.yaml";
log.info("新节点生成docker-compose文件路径:" + yamlFilePath);
if (!yamlFileService.writeObjectToYamlFile(peerComposeConfig, yamlFilePath)) {
return null;
}
// 生成 start-peer.sh
String newShFilePath = filePath + "start-peer.sh";
String srcShFilePath = modeService.getInitDir() + "template/start-peer.sh";
FileUtils.copyFile(new File(srcShFilePath), new File(newShFilePath));
return yamlFilePath;
}
}

View file

@ -0,0 +1,238 @@
package com.cgb.bcpinstall.config.configGenImpl;
import com.cgb.bcpinstall.common.entity.init.InitConfigEntity;
import com.cgb.bcpinstall.common.util.FileUtil;
import com.cgb.bcpinstall.config.FabricConfigGen;
import com.cgb.bcpinstall.service.ModeService;
import com.cgb.bcpinstall.service.YamlFileService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author zheng.li
* @date 2020/3/12 15:48
*/
@Service
@Slf4j
public class FabricConfigGenImpl implements FabricConfigGen {
private static final String CONFIGTX = "configtx";
private static final String CRYPTO = "crypto";
@Autowired
private ModeService modeService;
@Autowired
private YamlFileService yamlFileService;
@Override
public boolean configTxGen(InitConfigEntity initConfig) {
Map<Object, Object> configTxEntity = this.loadTemplate(CONFIGTX);
if (CollectionUtils.isEmpty(configTxEntity)) {
return false;
}
Map<Object, Object> ordererOrg = null;
Map<Object, Object> org1 = null;
List<Map<Object, Object>> organizations = (List<Map<Object, Object>>) configTxEntity.get("Organizations");
for (Map<Object, Object> item : organizations) {
if ("OrdererOrg".equals(item.get("Name"))) {
item.put("MSPDir", String.format("crypto-config/ordererOrganizations/%s/msp", initConfig.getOrdererDomain()));
ordererOrg = item;
} else {
org1 = item;
item.put("Name", initConfig.getOrgMSPID());
item.put("ID", initConfig.getOrgMSPID());
item.put("MSPDir", String.format("crypto-config/peerOrganizations/%s/msp", initConfig.getPeerDomain()));
Map<Object, Object> policies = (Map<Object, Object>) item.get("Policies");
Map<Object, Object> config = (Map<Object, Object>) policies.get("Readers");
config.put("Rule", String.format("OR('%s.admin','%s.peer','%s.client')", initConfig.getOrgMSPID(), initConfig.getOrgMSPID(), initConfig.getOrgMSPID()));
config = (Map<Object, Object>) policies.get("Writers");
config.put("Rule", String.format("OR('%s.admin','%s.client')", initConfig.getOrgMSPID(), initConfig.getOrgMSPID()));
config = (Map<Object, Object>) policies.get("Admins");
config.put("Rule", String.format("OR('%s.admin')", initConfig.getOrgMSPID()));
String peerHost = initConfig.getPeerHostConfig().keySet().iterator().next();
String peerIp = initConfig.getPeerHostConfig().get(peerHost);
int index = peerIp.lastIndexOf(":");
List<Map<Object, Object>> anchorPeers = (List<Map<Object, Object>>) item.get("AnchorPeers");
anchorPeers.get(0).put("Host", peerHost);
anchorPeers.get(0).put("Port", Integer.parseInt(peerIp.substring(index + 1)));
}
}
String firstOrdererHost = initConfig.getOrdererHostConfig().keySet().iterator().next();
String firstOrdererIp = initConfig.getOrdererHostConfig().get(firstOrdererHost);
int index = firstOrdererIp.lastIndexOf(":");
// Orderer
Map<Object, Object> orderer = (Map<Object, Object>) configTxEntity.get("Orderer");
List<String> orderAddresses = (List<String>) orderer.get("Addresses");
orderAddresses.clear();
orderAddresses.add(String.format(firstOrdererHost + firstOrdererIp.substring(index)));
// SampleMultiNodeEtcdRaft
Map<Object, Object> profile = (Map<Object, Object>) ((Map<Object, Object>) configTxEntity.get("Profiles")).get("SampleMultiNodeEtcdRaft");
Map<Object, Object> orderConfig = (Map<Object, Object>) profile.get("Orderer");
Map<String, Object> etcdRaftConfig = (Map<String, Object>) orderConfig.get("EtcdRaft");
List<Map<String, Object>> consenters = (List<Map<String, Object>>) (etcdRaftConfig).get("Consenters");
consenters.clear();
consenters.addAll(this.generateOrdersConfig(initConfig));
organizations = (List<Map<Object, Object>>) orderConfig.get("Organizations");
organizations.clear();
organizations.add(ordererOrg);
Map<Object, Object> capabilities = (Map<Object, Object>) orderConfig.get("Capabilities");
orderAddresses = (List<String>) orderConfig.get("Addresses");
orderAddresses.clear();
for (String host : initConfig.getOrdererHostConfig().keySet()) {
String ip = initConfig.getOrdererHostConfig().get(host);
orderAddresses.add(host + ip.substring(ip.lastIndexOf(":")));
}
orderConfig.clear();
orderConfig.putAll(orderer);
orderConfig.put("OrdererType", "etcdraft");
orderConfig.put("EtcdRaft", etcdRaftConfig);
orderConfig.put("Addresses", orderAddresses);
orderConfig.put("Organizations", organizations);
orderConfig.put("Capabilities", capabilities);
Map<Object, Object> application = (Map<Object, Object>) profile.get("Application");
organizations = (List<Map<Object, Object>>) application.get("Organizations");
organizations.clear();
organizations.add(ordererOrg);
Map<Object, Object> sampleConsortium = (Map<Object, Object>) ((Map<Object, Object>) profile.get("Consortiums")).get("SampleConsortium");
organizations = (List<Map<Object, Object>>) sampleConsortium.get("Organizations");
organizations.clear();
organizations.add(org1);
// PrivateChannel
profile = (Map<Object, Object>) ((Map<Object, Object>) configTxEntity.get("Profiles")).get("PrivateChannel");
application = (Map<Object, Object>) profile.get("Application");
organizations = (List<Map<Object, Object>>) application.get("Organizations");
organizations.clear();
organizations.add(org1);
// OneOrgChannel
profile = (Map<Object, Object>) ((Map<Object, Object>) configTxEntity.get("Profiles")).get("OneOrgChannel");
application = (Map<Object, Object>) profile.get("Application");
organizations = (List<Map<Object, Object>>) application.get("Organizations");
organizations.clear();
organizations.add(org1);
return writeYamlFile(configTxEntity, CONFIGTX);
}
/**
* 将配置信息写入configtx.yaml文件
*
* @param configTxEntity
* @return
*/
private boolean writeYamlFile(Map<Object, Object> configTxEntity, String fileName) {
String yamlFile = null;
if (fileName.equals(CONFIGTX)) {
yamlFile = modeService.getInitDir() + "fabric-net/cryptoAndConfig/configtx.yaml";
}
if (fileName.equals(CRYPTO)) {
yamlFile = modeService.getInitDir() + "fabric-net/cryptoAndConfig/crypto-config.yaml";
}
if (StringUtils.isEmpty(yamlFile)) {
return false;
}
return yamlFileService.writeObjectToYamlFile(configTxEntity, yamlFile);
}
/**
* 加载指定文件名称的文件模板
*
* @param fileName
* @return
*/
private Map<Object, Object> loadTemplate(String fileName) {
String txTempFile = null;
if (fileName.equals(CONFIGTX)) {
txTempFile = modeService.getInitDir() + "template/configtx.yaml";
}
if (fileName.equals(CRYPTO)) {
txTempFile = modeService.getInitDir() + "template/crypto-config.yaml";
}
if (StringUtils.isEmpty(txTempFile) || StringUtils.isEmpty(fileName)) {
return null;
}
Map<Object, Object> result = null;
try {
result = yamlFileService.loadYamlFile(txTempFile);
} catch (FileNotFoundException e) {
log.error("找不到指定文件,文件路径:" + txTempFile);
e.printStackTrace();
}
return result;
}
private List<Map<String, Object>> generateOrdersConfig(InitConfigEntity configEntity) {
String tlsFormat = "crypto-config/ordererOrganizations/%s/orderers/%s/tls/server.crt";
List<Map<String, Object>> config = new ArrayList<>();
for (String host : configEntity.getOrdererHostConfig().keySet()) {
String ip = configEntity.getOrdererHostConfig().get(host);
int index = ip.lastIndexOf(":");
Map<String, Object> orderConfig = new HashMap<>();
orderConfig.put("Host", host);
orderConfig.put("Port", Integer.parseInt(ip.substring(index + 1)));
String tls = String.format(tlsFormat, configEntity.getOrdererDomain(), host);
orderConfig.put("ClientTLSCert", tls);
orderConfig.put("ServerTLSCert", tls);
config.add(orderConfig);
}
return config;
}
@Override
public boolean cryptoGen(InitConfigEntity initConfig) {
Map<Object, Object> cryptoConfig = this.loadTemplate(CRYPTO);
List<Map<Object, Object>> ordererOrgs = (List<Map<Object, Object>>) cryptoConfig.get("OrdererOrgs");
ordererOrgs.get(0).put("Domain", initConfig.getOrdererDomain());
List<Map<Object, Object>> specs = (List<Map<Object, Object>>) ordererOrgs.get(0).get("Specs");
specs.clear();
for (String orderHost : initConfig.getOrdererHostConfig().keySet()) {
int index = orderHost.indexOf(".");
specs.add(new HashMap<Object, Object>() {{
put("Hostname", orderHost.substring(0, index));
}});
}
List<Map<Object, Object>> peerOrgs = (List<Map<Object, Object>>) cryptoConfig.get("PeerOrgs");
peerOrgs.get(0).put("Name", initConfig.getOrgMSPID().replace("MSP", ""));
peerOrgs.get(0).put("Domain", initConfig.getPeerDomain());
List<Map<Object, Object>> peerSpecs = (List<Map<Object, Object>>) peerOrgs.get(0).get("Specs");
peerSpecs.clear();
for (String peerHost : initConfig.getPeerHostConfig().keySet()) {
String peerHostName = peerHost.split("." + initConfig.getPeerDomain())[0];
peerSpecs.add(new HashMap<Object, Object>() {{
put("Hostname", peerHostName);
}});
}
return writeYamlFile(cryptoConfig, CRYPTO);
}
}

View file

@ -0,0 +1,428 @@
package com.cgb.bcpinstall.db;
import com.cgb.bcpinstall.db.table.NodeDO;
import com.cgb.bcpinstall.db.util.MapperUtil;
import com.cgb.bcpinstall.db.util.object.BaseDO;
import com.cgb.bcpinstall.db.util.object.Column;
import com.cgb.bcpinstall.db.util.object.Table;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.sql.Date;
import java.sql.*;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Component
public class CheckPointDb {
public boolean nodesTableEmpty() throws SQLException {
return this.findDO(new NodeDO()).isEmpty();
}
public Long addNodeRecord(NodeDO obj) throws SQLException {
synchronized (this) {
return executeInsert(MapperUtil.createMapper(obj.getClass()), MapperUtil.createInsertSql(obj));
}
}
public void deleteNodeRecord(NodeDO obj) throws SQLException {
synchronized (this) {
execute(MapperUtil.createMapper(obj.getClass()), MapperUtil.createDeleteByParamSql(obj));
}
}
public List<NodeDO> find(NodeDO nodeDO) throws SQLException {
synchronized (this) {
return this.findDO(nodeDO);
}
}
public boolean updateNode(NodeDO obj) throws SQLException {
synchronized (this) {
Table table = MapperUtil.createMapper(obj.getClass());
NodeDO param = new NodeDO();
param.setOrgMspId(obj.getOrgMspId());
param.setHostName(obj.getHostName());
param.setIp(obj.getIp());
param.setPort(obj.getPort());
List<NodeDO> found = findDO(param);
if (found.isEmpty()) {
return executeInsert(table, MapperUtil.createInsertSql(obj)) != null;
} else {
if (found.size() > 1) {
execute(table, MapperUtil.createDeleteByParamSql(param));
return executeInsert(table, MapperUtil.createInsertSql(obj)) != null;
} else {
NodeDO item = found.get(0);
if (item.getStatus() == obj.getStatus()) {
return false;
}
obj.setId(found.get(0).getId());
return executeUpdate(table, MapperUtil.createUpdateByIdSql(obj)) == 1;
}
}
}
}
private <T extends BaseDO> List<T> findDO(T obj) throws SQLException {
return find(obj, null, 0, 0);
}
/**
*
* @param obj
* @param orderBy
* @param pageIndex 从1开始
* @param pageSize
* @param <T>
* @return
* @throws SQLException
*/
private <T extends BaseDO> List<T> find(T obj, Map<String, Boolean> orderBy, int pageIndex, int pageSize) throws SQLException {
List<T> result = new ArrayList<>();
Class clazz = obj.getClass();
Table table = MapperUtil.createMapper(clazz);
checkAndCreateTable(table);
String sql = MapperUtil.generalFindSql(obj);
if (!CollectionUtils.isEmpty(orderBy)) {
StringBuilder orderByStr = new StringBuilder();
Set<String> orderFields = orderBy.keySet();
for (String f: orderFields) {
List<Column> cols = table.getFields().stream()
.filter(c -> c.getFieldName().equalsIgnoreCase(f) || c.getColumnName().equalsIgnoreCase(f))
.collect(Collectors.toList());
if (!cols.isEmpty()) {
if (orderByStr.length() == 0) {
orderByStr.append(" order by ");
}
orderByStr.append(cols.get(0).getColumnName()).append(orderBy.get(f) ? " asc," : " desc,");
}
}
String subSql = orderByStr.toString();
if (subSql.endsWith(",")) {
subSql = subSql.substring(0, subSql.length() - 1);
}
if (!subSql.isEmpty()) {
sql = sql + subSql;
}
}
if (pageIndex > 0 && pageSize > 0) {
sql = sql + " limit " + (pageIndex - 1) * pageSize + ", " + pageSize;
}
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = ConnectionPool.getInstance().getConnection();
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
List<Column> columns = table.getFields();
while (rs.next()) {
T rtObj = (T)clazz.newInstance();
for (Column col: columns) {
Object v = rs.getObject(col.getColumnName());
setFieldValue(rtObj, col, rs);
}
result.add(rtObj);
}
} catch (IllegalAccessException | InstantiationException e) {
e.printStackTrace();
} finally {
ConnectionPool.releaseConnection(conn, stmt, rs);
}
return result;
}
private <T extends BaseDO> int countOf(T obj) throws SQLException {
Class clazz = obj.getClass();
Table table = MapperUtil.createMapper(clazz);
checkAndCreateTable(table);
String sql = MapperUtil.generalCountSql(obj);
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = ConnectionPool.getInstance().getConnection();
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
if (rs.next()) {
return rs.getInt("total");
}
} finally {
ConnectionPool.releaseConnection(conn, stmt, rs);
}
return 0;
}
private static <T extends Enum<?>> T getEnumObject(String value, Class<T> clazz) {
if (!clazz.isEnum()) {
return null;
}
try {
T[] enumConstants = clazz.getEnumConstants();
for (T ec : enumConstants) {
if (((Enum<?>) ec).name().equals(value)) {
return ec;
}
}
return null;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private <T extends BaseDO> void setFieldValue(T rtObj, Column col, ResultSet rs) {
Field[] fields = rtObj.getClass().getDeclaredFields();
boolean found = false;
for (Field field: fields) {
field.setAccessible(true);
if (field.getName().equals(col.getFieldName())) {
found = true;
try {
Class type = field.getType();
if (type.isEnum()) {
field.set(rtObj, getEnumObject(col.getColumnName(), type));
} else if (type.equals(Long.class)) {
field.set(rtObj, rs.getLong(col.getColumnName()));
} else if (type.equals(String.class)) {
field.set(rtObj, rs.getString(col.getColumnName()));
} else if (type.equals(Date.class)) {
field.set(rtObj, rs.getDate(col.getColumnName()));
} else if (type.equals(Integer.class)) {
field.set(rtObj, rs.getInt(col.getColumnName()));
} else {
field.set(rtObj, rs.getObject(col.getColumnName()));
}
} catch (IllegalAccessException | SQLException e) {
e.printStackTrace();
}
}
}
if (!found) {
Class parent = rtObj.getClass().getSuperclass();
Field[] fieldsParent = parent.getDeclaredFields();
for (Field field: fieldsParent) {
field.setAccessible(true);
if (field.getName().equals(col.getFieldName())) {
try {
Class type = field.getType();
if (type.equals(Long.class)) {
field.set(rtObj, rs.getLong(col.getColumnName()));
} else if (type.equals(String.class)) {
field.set(rtObj, rs.getString(col.getColumnName()));
} else if (type.equals(java.util.Date.class)) {
field.set(rtObj, rs.getTimestamp(col.getColumnName()));
} else if (type.equals(Integer.class)) {
field.set(rtObj, rs.getInt(col.getColumnName()));
} else {
field.set(rtObj, rs.getObject(col.getColumnName()));
}
} catch (IllegalAccessException | SQLException e) {
e.printStackTrace();
}
}
}
}
}
private boolean execute(Table table, String sql) throws SQLException {
checkAndCreateTable(table);
Connection conn = null;
Statement stmt = null;
try {
conn = ConnectionPool.getInstance().getConnection();
stmt = conn.createStatement();
return stmt.execute(sql);
} finally {
ConnectionPool.releaseConnection(conn, stmt, null);
}
}
private Long executeInsert(Table table, String sql) throws SQLException {
checkAndCreateTable(table);
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = ConnectionPool.getInstance().getConnection();
stmt = conn.createStatement();
stmt.execute(sql, Statement.RETURN_GENERATED_KEYS);
rs = stmt.getGeneratedKeys();
if (rs.next()) {
return rs.getLong("id");
}
return 0L;
} finally {
ConnectionPool.releaseConnection(conn, stmt, rs);
}
}
private int executeUpdate(Table table, String sql) throws SQLException {
checkAndCreateTable(table);
Connection conn = null;
Statement stmt = null;
try {
conn = ConnectionPool.getInstance().getConnection();
stmt = conn.createStatement();
return stmt.executeUpdate(sql);
} finally {
ConnectionPool.releaseConnection(conn, stmt, null);
}
}
private void checkAndCreateTable(Table table) throws SQLException {
Connection conn = ConnectionPool.getInstance().getConnection();
DatabaseMetaData meta = conn.getMetaData();
ResultSet rsTables = meta.getTables(null, null, table.getTableName(), new String[] { "TABLE" });
Statement stmt = null;
if (!rsTables.next()) {
stmt = conn.createStatement();
stmt.execute(MapperUtil.createTableSql(table));
}
ConnectionPool.releaseConnection(conn, stmt, rsTables);
}
public <T extends BaseDO> Long executeInsertWithParametered(T obj, String sql) throws SQLException {
Table table = MapperUtil.createMapper(obj.getClass());
checkAndCreateTable(table);
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
conn = ConnectionPool.getInstance().getConnection();
stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
for (int i = 0; i < table.getFields().size(); ++i) {
Column c = table.getFields().get(i);
if (c.getColumnName().equals("id")) {
continue;
}
if (c.getColumnName().equals("revision")) {
stmt.setLong(i, 0);
} else if (c.getColumnName().equals("create_time")) {
stmt.setTimestamp(i, new Timestamp(System.currentTimeMillis()));
} else if (c.getColumnName().equals("modify_time")) {
stmt.setTimestamp(i, new Timestamp(System.currentTimeMillis()));
} else {
try {
Object val = MapperUtil.getFieldValue(obj, c.getFieldName());
if ("CLOB".equalsIgnoreCase(c.getDbType())) {
ByteArrayInputStream byteInputStream = new ByteArrayInputStream(val == null ? "".getBytes() : val.toString().getBytes());
stmt.setAsciiStream(i, byteInputStream);
}
else {
if (String.class.getName().equals(c.getType())) {
stmt.setString(i, val.toString());
} else if (java.util.Date.class.getName().equals(c.getType())) {
if (val == null) {
stmt.setTimestamp(i, new Timestamp(System.currentTimeMillis()));
} else {
stmt.setTimestamp(i, new Timestamp(((java.util.Date)val).getTime()));
}
} else {
stmt.setString(i, val == null ? "" : val.toString());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
stmt.executeUpdate();
rs = stmt.getGeneratedKeys();
if (rs.next()) {
return rs.getLong("id");
}
return 0L;
} finally {
ConnectionPool.releaseConnection(conn, stmt, rs);
}
}
public <T extends BaseDO> List<Long> findOnlyIds(T obj, Map<String, Boolean> orderBy, int pageIndex, int pageSize) throws SQLException {
List<Long> result = new ArrayList<>();
Class clazz = obj.getClass();
Table table = MapperUtil.createMapper(clazz);
checkAndCreateTable(table);
String sql = MapperUtil.generalFindIdSql(obj);
if (!CollectionUtils.isEmpty(orderBy)) {
StringBuilder orderByStr = new StringBuilder();
Set<String> orderFields = orderBy.keySet();
for (String f: orderFields) {
List<Column> cols = table.getFields().stream()
.filter(c -> c.getFieldName().equalsIgnoreCase(f) || c.getColumnName().equalsIgnoreCase(f))
.collect(Collectors.toList());
if (!cols.isEmpty()) {
if (orderByStr.length() == 0) {
orderByStr.append(" order by ");
}
orderByStr.append(cols.get(0).getColumnName()).append(orderBy.get(f) ? " asc," : " desc,");
}
}
String subSql = orderByStr.toString();
if (subSql.endsWith(",")) {
subSql = subSql.substring(0, subSql.length() - 1);
}
if (!subSql.isEmpty()) {
sql = sql + subSql;
}
}
if (pageIndex > 0 && pageSize > 0) {
sql = sql + " limit " + (pageIndex - 1) * pageSize + ", " + pageSize;
}
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = ConnectionPool.getInstance().getConnection();
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
List<Column> columns = table.getFields();
while (rs.next()) {
Long id = rs.getLong("id");
result.add(id);
}
} finally {
ConnectionPool.releaseConnection(conn, stmt, rs);
}
return result;
}
}

View file

@ -0,0 +1,78 @@
package com.cgb.bcpinstall.db;
import com.cgb.bcpinstall.common.util.FileUtil;
import com.cgb.bcpinstall.db.table.NodeDO;
import com.cgb.bcpinstall.db.util.MapperUtil;
import com.cgb.bcpinstall.db.util.object.Table;
import org.h2.jdbcx.JdbcConnectionPool;
import java.io.File;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class ConnectionPool {
private static ConnectionPool instance = null;
private JdbcConnectionPool jdbcConnectionPool = null;
private ConnectionPool() {
boolean needInit = false;
String dbFilePath = FileUtil.getUserDir() + "bcp-install";
if (!new File(dbFilePath + ".mv.db").exists()) {
needInit = true;
}
jdbcConnectionPool = JdbcConnectionPool.create("jdbc:h2:file:" + dbFilePath + ";database_to_upper=false;DB_CLOSE_ON_EXIT=FALSE", "sa", "");
jdbcConnectionPool.setMaxConnections(50);
if (needInit) {
try {
initDb();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
private void initDb() throws SQLException {
Connection conn = null;
Statement stmt = null;
try {
conn = getConnection();
stmt = conn.createStatement();
Table table = MapperUtil.createMapper(NodeDO.class);
String sql = MapperUtil.createTableSql(table);
stmt.execute(sql);
} catch (Exception e) {
e.printStackTrace();
} finally {
releaseConnection(conn, stmt, null);
}
}
public static void releaseConnection(Connection conn, Statement stmt,
ResultSet rs) throws SQLException {
if (rs != null) {
rs.close();
}
if (stmt != null) {
stmt.close();
}
if (conn != null) {
conn.close();
}
}
public static ConnectionPool getInstance() {
if (instance == null) {
instance = new ConnectionPool();
}
return instance;
}
public Connection getConnection() throws SQLException {
return jdbcConnectionPool.getConnection();
}
}

View file

@ -0,0 +1,34 @@
package com.cgb.bcpinstall.db.table;
import com.cgb.bcpinstall.common.entity.InstallStatusEnum;
import com.cgb.bcpinstall.common.entity.RoleEnum;
import com.cgb.bcpinstall.db.util.annotation.ColumnAnnotation;
import com.cgb.bcpinstall.db.util.annotation.TableAnnotation;
import com.cgb.bcpinstall.db.util.object.BaseDO;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@TableAnnotation("tb_nodes")
public class NodeDO extends BaseDO {
private static final long serialVersionUID = 6148451850282590664L;
@ColumnAnnotation(columnName = "org_msp_id", isMaster = true, dbType = "VARCHAR", length = 128)
private String orgMspId;
@ColumnAnnotation(columnName = "role", isMaster = true, dbType = "VARCHAR", length = 64)
private RoleEnum role;
@ColumnAnnotation(columnName = "host_name", isMaster = true, dbType = "VARCHAR", length = 128)
private String hostName;
@ColumnAnnotation(columnName = "ip_address", isMaster = true, dbType = "VARCHAR", length = 64)
private String ip;
@ColumnAnnotation(columnName = "port", dbType = "INTEGER")
private Integer port;
@ColumnAnnotation(columnName = "status", dbType = "VARCHAR", length = 64)
private InstallStatusEnum status;
}

View file

@ -0,0 +1,660 @@
package com.cgb.bcpinstall.db.util;
import com.cgb.bcpinstall.db.util.annotation.ColumnAnnotation;
import com.cgb.bcpinstall.db.util.annotation.TableAnnotation;
import com.cgb.bcpinstall.db.util.object.BaseDO;
import com.cgb.bcpinstall.db.util.object.Column;
import com.cgb.bcpinstall.db.util.object.Table;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MapperUtil {
public static final char UNDERLINE = '_';
public static String camelToUnderline(String param) {
if (param == null || "".equals(param.trim())) {
return "";
}
int len = param.length();
StringBuilder sb = new StringBuilder(len);
for (int i = 0; i < len; i++) {
char c = param.charAt(i);
if (Character.isUpperCase(c)) {
sb.append(UNDERLINE);
sb.append(Character.toLowerCase(c));
} else {
sb.append(c);
}
}
return sb.toString();
}
public static String underlineToCamel(String param) {
if (param == null || "".equals(param.trim())) {
return "";
}
int len = param.length();
StringBuilder sb = new StringBuilder(len);
for (int i = 0; i < len; i++) {
char c = param.charAt(i);
if (c == UNDERLINE) {
if (++i < len) {
sb.append(Character.toUpperCase(param.charAt(i)));
}
} else {
sb.append(c);
}
}
return sb.toString();
}
public static String underlineToCamel2(String param) {
if (param == null || "".equals(param.trim())) {
return "";
}
StringBuilder sb = new StringBuilder(param);
Matcher mc = Pattern.compile("_").matcher(param);
int i = 0;
while (mc.find()) {
int position = mc.end() - (i++);
// String.valueOf(Character.toUpperCase(sb.charAt(position)));
sb.replace(position - 1, position + 1, sb.substring(position, position + 1).toUpperCase());
}
return sb.toString();
}
/**
* 生成sql
*
* @param table
*/
public static String createTableSql(Table table) {
StringBuilder sb = new StringBuilder("CREATE TABLE ");
sb.append(table.getTableName()).append("(\n");
for (Column c : table.getFields()) {
if (c.getColumnName().equals("id")) {
sb.append("\t" + c.getColumnName()).append(" ").append(c.getDbType()).append(" NOT NULL AUTO_INCREMENT,\n");
continue;
}
sb.append("\t" + c.getColumnName()).append(" ").append(c.getDbType());
if (c.getDbType().equals("VARCHAR") || c.getDbType().equals("BIGINT")) {
sb.append("(").append(c.getLength()).append(") ");
} else if (c.getDbType().equals("DECIMAL")) {
sb.append("(15,4) ");
} else if (c.getDbType().equals("INT")) {
sb.append("(").append(c.getLength()).append(") ");
} else if (c.getDbType().equals("TIMESTAMP")) {
sb.append(" NULL ");
} else {
sb.append(" ");
}
sb.append(c.isNull() ? " " : "NOT NULL ");
sb.append(c.isUnique() ? " UNIQUE,\n" : ",\n");
}
// 添加默认字段
String s = sb.toString();
s = s + "\tPRIMARY KEY(id)\n)AUTO_INCREMENT=1;\n";
System.out.println(s);
return s;
}
/**
* 生成table
*
* @param clazz
* @return
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public static Table createMapper(Class clazz) {
Table table = new Table();
TableAnnotation tableAnno = (TableAnnotation) clazz.getAnnotation(TableAnnotation.class);
table.setClassName(clazz.getName());
table.setTableName(tableAnno.value());
Field[] fields = clazz.getDeclaredFields();
ColumnAnnotation column = null;
String fieldName = null;
Class type = null;
Class parent = clazz.getSuperclass();
Field[] fieldsParent = parent.getDeclaredFields();
List<Column> fieldList = new LinkedList<Column>();
Column c = null;
for (Field field : fieldsParent) {
if (field.getName().equals("serialVersionUID")) {
continue;
}
column = field.getAnnotation(ColumnAnnotation.class);
fieldName = field.getName();
type = field.getType();
c = new Column();
c.setColumnName(camelToUnderline(fieldName));
c.setType(type.getName());
c.setFieldName(fieldName);
if (column == null) {
c.setNull(true);
c.setLength(32);
if (Long.class.equals(field.getType())) {
c.setDbType("BIGINT");
c.setLength(18);
} else if (String.class.equals(field.getType())) {
c.setDbType("VARCHAR");
} else if (Integer.class.equals(field.getType())) {
c.setDbType("INTEGER");
} else if (Date.class.equals(field.getType())) {
c.setDbType("TIMESTAMP");
} else if (boolean.class.equals(field.getType())) {
c.setDbType("SMALLINT");
c.setLength(1);
} else if (Boolean.class.equals(field.getType())) {
c.setDbType("SMALLINT");
c.setLength(1);
} else {
c.setDbType("VARCHAR");
c.setLength(30);
}
} else {
if (StringUtils.isNotBlank(column.columnName())) {
c.setColumnName(column.columnName());
}
if (StringUtils.isBlank(column.dbType())) {
if (Long.class.equals(field.getType())) {
c.setDbType("BIGINT");
} else if (String.class.equals(field.getType())) {
c.setDbType("VARCHAR");
} else if (Integer.class.equals(field.getType())) {
c.setDbType("INTEGER");
} else if (Date.class.equals(field.getType())) {
c.setDbType("TIMESTAMP");
} else if (boolean.class.equals(field.getType())) {
c.setDbType("SMALLINT");
} else if (Boolean.class.equals(field.getType())) {
c.setDbType("SMALLINT");
} else {
c.setDbType("VARCHAR");
}
} else {
c.setDbType(column.dbType());
}
c.setLength(column.length());
c.setNull(column.isNull());
c.setUnique(column.isUnique());
c.setMaster(column.isMaster());
c.setLike(column.isLike());
}
fieldList.add(c);
}
List<Column> fieldListSub = new LinkedList<>();
for (Field field : fields) {
if (field.getName().equals("serialVersionUID")) {
continue;
}
column = field.getAnnotation(ColumnAnnotation.class);
fieldName = field.getName();
type = field.getType();
c = new Column();
c.setColumnName(camelToUnderline(fieldName));
c.setType(type.getName());
c.setFieldName(fieldName);
if (column == null) {
c.setNull(true);
c.setLength(32);
if (Long.class.equals(field.getType())) {
c.setDbType("BIGINT");
c.setLength(18);
} else if (String.class.equals(field.getType())) {
c.setDbType("VARCHAR");
c.setLength(32);
} else if (Integer.class.equals(field.getType())) {
c.setDbType("INTEGER");
c.setLength(11);
} else if (Date.class.equals(field.getType())) {
c.setDbType("TIMESTAMP");
} else if (boolean.class.equals(field.getType())) {
c.setDbType("SMALLINT");
c.setLength(1);
} else if (Boolean.class.equals(field.getType())) {
c.setDbType("SMALLINT");
c.setLength(1);
} else {
c.setDbType("VARCHAR");
c.setLength(32);
}
} else {
if (StringUtils.isNotBlank(column.columnName())) {
c.setColumnName(column.columnName());
}
if (StringUtils.isBlank(column.dbType())) {
if (Long.class.equals(field.getType())) {
c.setDbType("BIGINT");
} else if (String.class.equals(field.getType())) {
c.setDbType("VARCHAR");
} else if (Integer.class.equals(field.getType())) {
c.setDbType("INTEGER");
} else if (Date.class.equals(field.getType())) {
c.setDbType("TIMESTAMP");
} else if (boolean.class.equals(field.getType())) {
c.setDbType("SMALLINT");
} else if (Boolean.class.equals(field.getType())) {
c.setDbType("SMALLINT");
} else {
c.setDbType("VARCHAR");
}
} else {
c.setDbType(column.dbType());
}
c.setLength(column.length());
c.setNull(column.isNull());
c.setUnique(column.isUnique());
c.setMaster(column.isMaster());
c.setLike(column.isLike());
}
fieldListSub.add(c);
}
fieldList.addAll(1, fieldListSub);
table.setFields(fieldList);
return table;
}
@SuppressWarnings({"unchecked", "rawtypes"})
public static <T> Object getFieldValue(T obj, String fieldName) throws IllegalAccessException, NoSuchFieldException {
Class clazz = obj.getClass();
Class parent = clazz.getSuperclass();
Field[] fieldsParent = parent.getDeclaredFields();
for (Field field : fieldsParent) {
if (field.getName().equalsIgnoreCase(fieldName)) {
field.setAccessible(true);
return field.get(obj);
}
}
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.getName().equalsIgnoreCase(fieldName)) {
field.setAccessible(true);
return field.get(obj);
}
}
return null;
}
public static <T extends BaseDO> String createDeleteByIdSql(T obj) {
Table table = createMapper(obj.getClass());
return "delete from " + table.getTableName() + " where id=" + obj.getId();
}
public static <T extends BaseDO> String createDeleteByParamSql(T obj) {
Table table = createMapper(obj.getClass());
StringBuilder builder = new StringBuilder();
boolean first = true;
for (Column c : table.getFields()) {
Object val = null;
try {
val = getFieldValue(obj, c.getFieldName());
} catch (Exception e) {
e.printStackTrace();
continue;
}
if (val == null) {
continue;
}
if (first) {
first = false;
builder.append(" ");
} else {
builder.append(" and ");
}
builder.append(" ").append(c.getColumnName()).append("=");
if (val.getClass().isEnum()) {
builder.append("'").append(val == null ? "" : val.toString()).append("'");
} else if (String.class.getName().equals(c.getType())) {
builder.append("'").append(val.toString()).append("'");
} else if (Date.class.getName().equals(c.getType())) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
builder.append("'").append(dateFormat.format((Date) val)).append("'");
} else {
builder.append(val.toString());
}
}
String sql = "delete from " + table.getTableName();
if (!builder.toString().isEmpty()) {
sql = sql + " where " + builder.toString();
}
return sql;
}
public static <T extends BaseDO> String createInsertSql(T obj) {
Table table = createMapper(obj.getClass());
StringBuilder sql = new StringBuilder();
sql.append("insert into ").append(table.getTableName()).append("\n \t").append("(");
StringBuilder insertColumn = new StringBuilder();
StringBuilder insertValues = new StringBuilder();
for (Column c : table.getFields()) {
if (c.getColumnName().equals("id")) {
continue;
}
insertColumn.append(c.getColumnName()).append(",");
if (c.getColumnName().equals("revision")) {
insertValues.append("\t 0, ");
continue;
} else if (c.getColumnName().equals("create_time")) {
insertValues.append("\t current_timestamp,");
} else if (c.getColumnName().equals("modify_time")) {
insertValues.append("\t current_timestamp,");
} else {
try {
Object val = getFieldValue(obj, c.getFieldName());
if (val.getClass().isEnum()) {
insertValues.append("\t '").append(val == null ? "" : val.toString()).append("',");
} else if (String.class.getName().equals(c.getType())) {
insertValues.append("\t '").append(val == null ? "" : val.toString()).append("',");
} else if (Date.class.getName().equals(c.getType())) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
insertValues.append("\t '").append(val == null ? "current_timestamp" : dateFormat.format((Date) val)).append("',");
} else {
insertValues.append("\t ").append(val == null ? "0" : val.toString()).append(",");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
String columns = insertColumn.toString();
String values = insertValues.toString();
sql.append(columns, 0, columns.length() - 1).append(") \n \t values \n \t (").append(values, 0, values.length() - 1).append(") ");
return sql.toString();
}
public static <T extends BaseDO> String createUpdateByIdSql(T obj) {
Table table = createMapper(obj.getClass());
StringBuilder stringBuilder = new StringBuilder("update " + table.getTableName() + " set ");
for (Column c : table.getFields()) {
if (c.getColumnName().equals("id") || c.getColumnName().equals("revision")
|| c.getColumnName().equals("create_time") || c.getColumnName().equals("modify_time")) {
continue;
}
try {
Object val = getFieldValue(obj, c.getFieldName());
if (val == null) {
continue;
}
stringBuilder.append(c.getColumnName()).append("=");
if (String.class.getName().equals(c.getType())) {
stringBuilder.append("'").append(val.toString()).append("',\t");
} else if (Date.class.getName().equals(c.getType())) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
stringBuilder.append("'").append(dateFormat.format((Date) val)).append("',\t");
} else {
stringBuilder.append(val.toString()).append(",\t");
}
} catch (Exception e) {
e.printStackTrace();
;
}
}
try {
stringBuilder.append("revision=revision+1, modify_time=current_timestamp where id = ").append(Objects.requireNonNull(getFieldValue(obj, "id")).toString());
} catch (Exception e) {
e.printStackTrace();
}
return stringBuilder.toString();
}
/**
* 生成可根据主查询字段查询语句
*/
public static <T extends BaseDO> String generalFindByMasterSql(T obj) {
Table table = createMapper(obj.getClass());
//获取可通过其查询的字段
List<Column> masters = new ArrayList<>();
for (Column col : table.getFields()) {
if (col.isMaster()) {
masters.add(col);
}
}
if (masters.isEmpty()) {
return null;
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("select * from ").append(table.getTableName()).append(" where ");
// 针对每个master生成对应的语句element
boolean first = true;
for (Column master : masters) {
if (first) {
first = false;
} else {
stringBuilder.append(" and ");
}
try {
Object val = getFieldValue(obj, master.getFieldName());
if (val == null) {
continue;
}
stringBuilder.append(" ").append(master.getColumnName()).append("=");
if (String.class.getName().equals(master.getType())) {
stringBuilder.append(" '").append(val.toString()).append("',");
} else if (Date.class.getName().equals(master.getType())) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
stringBuilder.append(" '").append(dateFormat.format((Date) val)).append("',");
} else {
stringBuilder.append(" ").append(val.toString()).append(",");
}
} catch (Exception e) {
e.printStackTrace();
;
}
}
String sql = stringBuilder.toString();
return sql.substring(0, sql.length() - 1);
}
/**
* 生成所有字段的查询sql
*
* @param obj
* @param <T>
* @return
*/
public static <T extends BaseDO> String generalCountSql(T obj) {
Table table = createMapper(obj.getClass());
List<Column> columns = table.getFields();
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("select count(*) as total from ").append(table.getTableName()).append(" where ");
// 针对每个master生成对应的语句element
boolean first = true;
for (Column master : columns) {
try {
Object val = getFieldValue(obj, master.getFieldName());
if (val == null) {
continue;
}
if (first) {
first = false;
} else {
stringBuilder.append(" and ");
}
stringBuilder.append(" ").append(master.getColumnName()).append("=");
if (String.class.getName().equals(master.getType())) {
stringBuilder.append(" '").append(val.toString()).append("'");
} else if (Date.class.getName().equals(master.getType())) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
stringBuilder.append(" '").append(dateFormat.format((Date) val)).append("'");
} else {
stringBuilder.append(" ").append(val.toString());
}
} catch (Exception e) {
e.printStackTrace();
;
}
}
return stringBuilder.toString();
}
/**
* 生成所有字段的查询sql
*
* @param obj
* @param <T>
* @return
*/
public static <T extends BaseDO> String generalFindSql(T obj) {
Table table = createMapper(obj.getClass());
List<Column> columns = table.getFields();
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("select * from ").append(table.getTableName());
// 针对每个master生成对应的语句element
StringBuilder whereBuilder = new StringBuilder();
boolean first = true;
for (Column master : columns) {
try {
Object val = getFieldValue(obj, master.getFieldName());
if (val == null) {
continue;
}
if (first) {
first = false;
} else {
whereBuilder.append(" and ");
}
whereBuilder.append(" ").append(master.getColumnName()).append("=");
if (val.getClass().isEnum()) {
whereBuilder.append(" '").append(val.toString()).append("'");
} else if (String.class.getName().equals(master.getType())) {
whereBuilder.append(" '").append(val.toString()).append("'");
} else if (Date.class.getName().equals(master.getType())) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
whereBuilder.append(" '").append(dateFormat.format((Date) val)).append("'");
} else {
whereBuilder.append(" ").append(val.toString());
}
} catch (Exception e) {
e.printStackTrace();
;
}
}
if (!whereBuilder.toString().isEmpty()) {
stringBuilder.append(" where ").append(whereBuilder.toString());
}
return stringBuilder.toString();
}
public static String createBatchInsertSql(Table table) {
StringBuilder sql = new StringBuilder();
sql.append("insert into ").append(table.getTableName()).append("\n \t").append("(");
StringBuilder insertColumn = new StringBuilder();
StringBuilder values = new StringBuilder();
for (Column c : table.getFields()) {
if (c.getColumnName().equals("id")) {
continue;
}
insertColumn.append(c.getColumnName()).append(",");
if (c.getColumnName().equals("revision")) {
values.append("0,\n \t");
continue;
} else if (c.getColumnName().equals("create_time")) {
values.append("\t current_timestamp,\n");
} else if (c.getColumnName().equals("modify_time")) {
values.append("\t currsssent_timestamp, \n");
} else {
values.append("\t \t #{").append("item." + c.getFieldName()).append(", ").append("jdbcType=").append(c.getDbType()).append(", javaType=").append(c.getType()).append("},\n");
}
}
sql.append(insertColumn.toString().substring(0, insertColumn.toString().length() - 1)).append(") \n \t values \n \t");
return sql.toString();
}
public static <T extends BaseDO> String generalFindIdSql(T obj) {
Table table = createMapper(obj.getClass());
List<Column> columns = table.getFields();
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("select id from ").append(table.getTableName()).append(" where ");
// 针对每个master生成对应的语句element
boolean first = true;
for (Column master : columns) {
try {
Object val = getFieldValue(obj, master.getFieldName());
if (val == null) {
continue;
}
if (first) {
first = false;
} else {
stringBuilder.append(" and ");
}
stringBuilder.append(" ").append(master.getColumnName()).append("=");
if (String.class.getName().equals(master.getType())) {
stringBuilder.append(" '").append(val.toString()).append("'");
} else if (Date.class.getName().equals(master.getType())) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
stringBuilder.append(" '").append(dateFormat.format((Date) val)).append("'");
} else {
stringBuilder.append(" ").append(val.toString());
}
} catch (Exception e) {
e.printStackTrace();
;
}
}
return stringBuilder.toString();
}
public static <T extends BaseDO> String createParameteredInsertSql(T obj) {
Table table = createMapper(obj.getClass());
StringBuilder sql = new StringBuilder();
sql.append("insert into ").append(table.getTableName()).append("\n \t").append("(");
StringBuilder insertColumn = new StringBuilder();
StringBuilder insertValues = new StringBuilder();
for (Column c : table.getFields()) {
if (c.getColumnName().equals("id")) {
continue;
}
insertColumn.append(c.getColumnName()).append(",");
insertValues.append(" ?,");
}
String columns = insertColumn.toString();
String values = insertValues.toString();
sql.append(columns, 0, columns.length() - 1).append(") \n \t values \n \t (").append(values, 0, values.length() - 1).append(") ");
return sql.toString();
}
}

View file

@ -0,0 +1,55 @@
package com.cgb.bcpinstall.db.util.annotation;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD })
@Inherited
public @interface ColumnAnnotation {
/**
* 列名
*
* @return
*/
String columnName();
/**
* 数据库类型
*
* @return
*/
String dbType();
/**
* 显示长度
*
* @return
*/
int length() default 32;
/**
* 是否为空
*
* @return
*/
boolean isNull() default true;
/**
* 是否唯一
*
* @return
*/
boolean isUnique() default false;
/**
* 是否可通过字段查询
*/
boolean isMaster() default false;
/**
* 是否模糊查询
* @return
*/
boolean isLike() default false;
}

View file

@ -0,0 +1,16 @@
package com.cgb.bcpinstall.db.util.annotation;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
@Inherited
public @interface TableAnnotation {
/**
* 表名
*
* @return
*/
String value();
}

View file

@ -0,0 +1,38 @@
package com.cgb.bcpinstall.db.util.object;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.io.Serializable;
import java.util.Date;
@Getter
@Setter
public class BaseDO implements Serializable {
/**
* 自增主键
*/
private Long id;
/**
* 数据版本
*/
private Long revision;
/**
* 数据创建时间
*/
private Date createTime;
/**
* 数据修改时间
*/
private Date modifyTime;
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
}

View file

@ -0,0 +1,62 @@
package com.cgb.bcpinstall.db.util.object;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
@Getter
@Setter
public class Column implements Serializable {
private static final long serialVersionUID = 4765664012786336010L;
private String columnName;
private String type;
private String fieldName;
private String dbType;
private int length;
private boolean isNull;
private boolean isUnique;
private boolean isMaster;
private boolean isLike;
public Column(String columnName, String type, String fieldName, String dbType){
super();
this.columnName = columnName;
this.type = type;
this.fieldName = fieldName;
this.dbType = dbType;
}
public Column(String columnName, String type, String fieldName, String dbType,boolean isLike){
super();
this.columnName = columnName;
this.type = type;
this.fieldName = fieldName;
this.dbType = dbType;
this.isLike = isLike;
}
public Column(String columnName, String type, String fieldName, String dbType, int length, boolean isNull,
boolean isUnique,boolean isMaster){
super();
this.columnName = columnName;
this.type = type;
this.fieldName = fieldName;
this.dbType = dbType;
this.length = length;
this.isNull = isNull;
this.isUnique = isUnique;
this.isMaster = isMaster;
}
public Column(){
super();
}
@Override
public String toString() {
return "Column [columnName=" + columnName + ", type=" + type + ", fieldName=" + fieldName + ", dbType="
+ dbType + ", length=" + length + ", isNull=" + isNull + "]";
}
}

View file

@ -0,0 +1,34 @@
package com.cgb.bcpinstall.db.util.object;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
import java.util.List;
@Getter
@Setter
public class Table implements Serializable {
private static final long serialVersionUID = 1093724215557902949L;
private String tableName;
private String className;
private List<Column> fields;
public Table(String tableName, String className, List<Column> fields){
super();
this.tableName = tableName;
this.className = className;
this.fields = fields;
}
public Table(){
super();
}
@Override
public String toString() {
return "Table [tableName=" + tableName + ", className=" + className + ", fields=" + fields + "]";
}
}

View file

@ -0,0 +1,195 @@
package com.cgb.bcpinstall.service;
import com.alibaba.fastjson.JSONObject;
import com.cgb.bcpinstall.common.entity.RoleEnum;
import com.cgb.bcpinstall.common.entity.init.InitConfigEntity;
import com.cgb.bcpinstall.common.util.FileUtil;
import com.cgb.bcpinstall.common.util.ProcessUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 环境设置服务类
*
* @author zheng.li
* @date 2020/3/2 14:56
*/
@Service
@Slf4j
public class EnvironmentService {
public void parseHostConfig(Map<String, String> hostConfig, Map<String, String> initFileConfig) {
for (String host : initFileConfig.keySet()) {
String ip = initFileConfig.get(host);
int index = ip.lastIndexOf(":");
ip = ip.substring(0, index);
hostConfig.put(host, ip);
}
}
/**
* 获取角色需要设置 hosts 文件的内容
*
* @param role
* @return
*/
public Map<String, String> getRoleNeedSetHost(RoleEnum role, InitConfigEntity configEntity) {
Map<String, String> hosts = new HashMap<>();
switch (role) {
case PEER:
parseHostConfig(hosts, configEntity.getPeerHostConfig());
break;
case ORDER:
parseHostConfig(hosts, configEntity.getOrdererHostConfig());
break;
default:
break;
}
return hosts;
}
/**
* 1. host文件修改
* 2. 端口加入防火墙
*
* @param ports
* @param hosts
*/
public void envSet(List<String> ports, Map<String, String> hosts) {
boolean append = true;
if (CollectionUtils.isEmpty(hosts)) {
return;
}
log.info(String.format("写入 hosts 文件: %s", JSONObject.toJSONString(hosts)));
try {
String hostContent = FileUtil.getFileContent("/etc/hosts");
log.info("写入 hosts 文件,hostContent=" + hostContent);
String[] hostConfigArray = hostContent.split("\n");
StringBuilder oldHostBuilder = new StringBuilder();
StringBuilder newHostBuilder = new StringBuilder();
for (String host : hosts.keySet()) {
String ip = hosts.get(host);
if (!hostContent.contains(host)) {
newHostBuilder.append("\n").append(ip).append(" ").append(host);
} else {
for (int i = 0; i < hostConfigArray.length; i++) {
String ipHost = ip + " " + host;
if (hostConfigArray[i].contains(host) && !hostConfigArray[i].equals(ipHost)) {
hostConfigArray[i] = ipHost;
append = false;
}
}
}
}
if (!append) {
oldHostBuilder.append(String.join("\n", hostConfigArray));
log.info("写入 hosts 文件,hostConfigArray.build=" + oldHostBuilder.toString());
}
oldHostBuilder.append(newHostBuilder);
FileOutputStream fos = new FileOutputStream(new File("/etc/hosts"), append);
fos.write(oldHostBuilder.toString().getBytes());
fos.close();
} catch (IOException e) {
log.error("写入/etc/hosts文件异常", e);
e.printStackTrace();
}
// 防火墙
if (ports.stream().noneMatch("2375"::equals)) {
ports.add("2375");
}
log.info(String.format("端口加入防火墙: %s", ports.stream().collect(Collectors.joining(","))));
for (String port : ports) {
addPortIntoFirewall(port);
}
}
public void addPortIntoFirewall(String port) {
boolean succ = false;
try {
String cmd = String.format("firewall-cmd --permanent --zone=public --add-port=%s/tcp", port);
ProcessUtil.Result res = ProcessUtil.execCmd(cmd, null, "./");
if (res.getCode() == 0) {
ProcessUtil.execCmd("firewall-cmd --reload", null, "./");
succ = true;
}
} catch (Exception e) {
log.error("调用 firewall-cmd 添加端口异常", e);
e.printStackTrace();
}
if (!succ) {
try {
String cmd = String.format("iptables -I INPUT -p tcp --dport %s -j ACCEPT", port);
ProcessUtil.Result res = ProcessUtil.execCmd(cmd, null, "./");
if (res.getCode() == 0) {
ProcessUtil.execCmd("service iptables save", null, "./");
}
} catch (Exception e) {
log.error("调用 iptables 添加端口异常", e);
e.printStackTrace();
}
}
}
public void updateNewPeerHostPort(Map<String, String> diffPeerHostConfig) {
Map<String, String> hosts = new HashMap<>(16);
List<String> ports = new ArrayList<>();
for (String host : diffPeerHostConfig.keySet()) {
String ipPort = diffPeerHostConfig.get(host);
String ip = ipPort.split(":")[0];
String port = ipPort.split(":")[1];
ports.add(port);
hosts.put(host, ip);
}
this.envSet(ports, hosts);
}
public void removePortFromFirewall(String port) {
boolean succ = false;
try {
String cmd = String.format("firewall-cmd --permanent --zone=public --remove-port=%s/tcp", port);
ProcessUtil.Result res = ProcessUtil.execCmd(cmd, null, "./");
if (res.getCode() == 0) {
ProcessUtil.execCmd("firewall-cmd --reload", null, "./");
succ = true;
}
} catch (Exception e) {
log.error("调用 firewall-cmd 添加端口异常", e);
e.printStackTrace();
}
if (!succ) {
try {
String cmd = String.format("iptables -D INPUT -p tcp --dport %s -j ACCEPT", port);
ProcessUtil.Result res = ProcessUtil.execCmd(cmd, null, "./");
if (res.getCode() == 0) {
ProcessUtil.execCmd("service iptables save", null, "./");
}
} catch (Exception e) {
log.error("调用 iptables 添加端口异常", e);
e.printStackTrace();
}
}
}
}

View file

@ -0,0 +1,267 @@
package com.cgb.bcpinstall.service;
import com.cgb.bcpinstall.common.entity.init.InitConfigEntity;
import com.cgb.bcpinstall.common.util.FileUtil;
import com.cgb.bcpinstall.common.util.NetUtil;
import com.cgb.bcpinstall.common.util.ProcessUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* fabric-cLi的服务类
*
* @author zheng.li
* @date 2020/3/2 15:22
*/
@Service
@Slf4j
public class FabricCliService {
@Autowired
private ModeService modeService;
@Autowired
private YamlFileService yamlFileService;
/**
* 获取创世区块
*
* @param configEntity
* @return
*/
public boolean fetchGenesisBlock(InitConfigEntity configEntity) {
try {
FileUtils.copyFile(new File(modeService.getInitDir() + "template/fetchGenesisBlock.sh"), new File(modeService.getInstallPath() + "cli/scripts/fetchGenesisBlock.sh"));
} catch (IOException e) {
log.error("复制脚本文件异常", e);
e.printStackTrace();
return false;
}
String firstOrdererHost = configEntity.getOrdererHostConfig().keySet().iterator().next();
String ip = configEntity.getOrdererHostConfig().get(firstOrdererHost);
String firstOrdererHostAddress = firstOrdererHost + ip.substring(ip.lastIndexOf(":"));
String CHANNEL_NAME = configEntity.getNetwork() + "-sys-channel";
String ORDERER_CA = String.format("/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/%s/orderers/%s/msp/tlscacerts/tlsca.%s-cert.pem", configEntity.getOrdererDomain(), firstOrdererHost, configEntity.getOrdererDomain());
String CORE_PEER_LOCALMSPID = "OrdererMSP";
String CORE_PEER_ADDRESS = firstOrdererHostAddress;
String CORE_PEER_TLS_ROOTCERT_FILE = String.format("/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/%s/orderers/%s/tls/ca.crt", configEntity.getOrdererDomain(), firstOrdererHost);
String CORE_PEER_MSPCONFIGPATH = String.format("/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/%s/users/Admin@%s/msp", configEntity.getOrdererDomain(), configEntity.getOrdererDomain());
String cmd = "docker exec cli bash scripts/fetchGenesisBlock.sh " + CHANNEL_NAME + " " + ORDERER_CA + " " + CORE_PEER_LOCALMSPID + " " + CORE_PEER_ADDRESS + " " + CORE_PEER_TLS_ROOTCERT_FILE + " " + CORE_PEER_MSPCONFIGPATH;
try {
ProcessUtil.execCmd(cmd, null, modeService.getInstallPath() + "cli");
File installGenesisFile = new File(modeService.getInstallPath() + "channel-artifacts" + File.separator + "genesis.block");
if (installGenesisFile.exists()) {
installGenesisFile.delete();
}
File initPathGenesisFile = new File(modeService.getInitDir() + "fabric-net/cryptoAndConfig/channel-artifacts" + File.separator + "genesis.block");
if (initPathGenesisFile.exists()) {
initPathGenesisFile.delete();
}
FileUtils.copyFile(new File("/var/run/genesis.block"), new File(modeService.getInstallPath() + "channel-artifacts" + File.separator + "genesis.block"));
FileUtils.copyFile(new File("/var/run/genesis.block"), initPathGenesisFile);
} catch (Exception e) {
log.error(String.format("执行脚本获取通道 %s 配置异常", CHANNEL_NAME), e);
e.printStackTrace();
return false;
}
return true;
}
/**
* 通过cli容器获取本机构所以节点加入的通道集合
*
* @param initConfigEntity
* @return
* @throws IOException
*/
public List<String> getAllChannels(InitConfigEntity initConfigEntity) throws IOException {
List<String> channelList = new ArrayList<>();
FileUtils.copyFile(new File(modeService.getInitDir() + "template/list-channels.sh"), new File(modeService.getInstallPath() + "cli/scripts/list-channels.sh"));
for (String host : initConfigEntity.getPeerHostConfig().keySet()) {
String ip = initConfigEntity.getPeerHostConfig().get(host);
int index = ip.lastIndexOf(":");
String port = ip.substring(index + 1);
String CORE_PEER_ADDRESS = host + ":" + port;
String CORE_PEER_TLS_ROOTCERT_FILE = String.format("/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/%s/peers/%s/tls/ca.crt", initConfigEntity.getPeerDomain(), host);
String CORE_PEER_TLS_CERT_FILE = String.format("/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/%s/peers/%s/tls/server.crt", initConfigEntity.getPeerDomain(), host);
String CORE_PEER_TLS_KEY_FILE = String.format("/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/%s/peers/%s/tls/server.key", initConfigEntity.getPeerDomain(), host);
try {
ProcessUtil.Result result = ProcessUtil.execCmd("docker exec cli bash scripts/list-channels.sh " + CORE_PEER_ADDRESS + " " + CORE_PEER_TLS_ROOTCERT_FILE + " " + CORE_PEER_TLS_CERT_FILE + " " + CORE_PEER_TLS_KEY_FILE, null, modeService.getInstallPath() + "cli");
if (result.getCode() == 0) {
String output = result.getData();
int i = output.indexOf("joined:");
output = output.substring(i + "joined:".length());
if (!StringUtils.isEmpty(output)) {
output = output.trim();
String[] channels = output.split("[\n]");
if (channels != null && channels.length > 0) {
for (String c : channels) {
c = c.trim();
if (StringUtils.isEmpty(c)) {
continue;
}
channelList.add(c);
}
}
}
}
} catch (Exception e) {
log.error("执行 docker 脚步获取通道异常", e);
e.printStackTrace();
}
}
return channelList;
}
/**
* 启动一个cli容器
*
* @param destFilePath
* @param initConfigEntity
* @return
*/
public boolean createCliContainer(String destFilePath, InitConfigEntity initConfigEntity) {
if (!destFilePath.endsWith(File.separator)) {
destFilePath = destFilePath + File.separator;
}
FileUtil.makeFilePath(destFilePath + "scripts", true);
try {
if (!this.createCliYamlFile(destFilePath, initConfigEntity)) {
log.error("创建cli容器相关文件失败");
return false;
}
} catch (IOException e) {
log.error("创建cli容器相关文件异常", e);
e.printStackTrace();
return false;
}
try {
ProcessUtil.Result result = ProcessUtil.execCmd("bash " + destFilePath + "start-peer.sh startCli", null, destFilePath);
if (result.getCode() == 0) {
log.info("启动 cli 容器成功");
return true;
}
} catch (Exception e) {
log.error("执行启动 cli 容器的脚步异常", e);
e.printStackTrace();
}
return false;
}
public boolean createCliYamlFile(String destFilePath, InitConfigEntity initConfig) throws IOException {
Map<Object, Object> peerComposeConfig = yamlFileService.loadYamlFile(modeService.getInitDir() + "template/docker-compose-peer.yaml");
Map<Object, Object> networks = (Map<Object, Object>) peerComposeConfig.get("networks");
networks.clear();
String network = initConfig.getNetwork() + "-cli";
networks.put(network, null);
peerComposeConfig.remove("volumes");
Map<Object, Object> services = (Map<Object, Object>) peerComposeConfig.get("services");
Map<Object, Object> cliConfig = (Map<Object, Object>) services.get("cli");
services.clear();
cliConfig.remove("depends_on");
String orgUrl = initConfig.getPeerDomain();
String peerHost = initConfig.getPeerHostConfig().keySet().iterator().next();
String peerIp = initConfig.getPeerHostConfig().get(peerHost);
String onlyHost = peerHost.substring(0, peerHost.indexOf("."));
List<String> newEnvironment = new ArrayList<>();
List<String> environment = (List<String>) cliConfig.get("environment");
for (String oldEnv : environment) {
String newEnv;
if (oldEnv.contains("CORE_PEER_ADDRESS")) {
newEnv = "CORE_PEER_ADDRESS=" + peerHost + peerIp.substring(peerIp.lastIndexOf(":"));
} else if (oldEnv.contains("CORE_PEER_LOCALMSPID")) {
newEnv = "CORE_PEER_LOCALMSPID=" + initConfig.getOrgMSPID();
} else if (oldEnv.contains("CORE_PEER_TLS_CERT_FILE")) {
newEnv = String.format(oldEnv, orgUrl, onlyHost);
} else if (oldEnv.contains("CORE_PEER_TLS_KEY_FILE")) {
newEnv = String.format(oldEnv, orgUrl, onlyHost);
} else if (oldEnv.contains("CORE_PEER_TLS_ROOTCERT_FILE")) {
newEnv = String.format(oldEnv, orgUrl, onlyHost);
} else if (oldEnv.contains("CORE_PEER_MSPCONFIGPATH")) {
newEnv = String.format(oldEnv, orgUrl, orgUrl);
} else {
newEnv = oldEnv;
}
newEnvironment.add(newEnv);
}
cliConfig.put("environment", newEnvironment);
cliConfig.put("networks", new ArrayList<String>() {{
add(network);
}});
List<String> extraHosts = new ArrayList<>();
for (String eHost : initConfig.getOrdererHostConfig().keySet()) {
String eIp = initConfig.getOrdererHostConfig().get(eHost);
eIp = eIp.substring(0, eIp.lastIndexOf(":"));
if (eIp.equalsIgnoreCase("127.0.0.1")) {
eIp = NetUtil.getMyNormalIP();
}
extraHosts.add(eHost + ":" + eIp);
}
for (String eHost : initConfig.getPeerHostConfig().keySet()) {
String eIp = initConfig.getPeerHostConfig().get(eHost);
eIp = eIp.substring(0, eIp.lastIndexOf(":"));
if (eIp.equalsIgnoreCase("127.0.0.1")) {
eIp = NetUtil.getMyNormalIP();
}
extraHosts.add(eHost + ":" + eIp);
}
cliConfig.put("extra_hosts", extraHosts);
services.put("cli", cliConfig);
if (!destFilePath.endsWith(File.separator)) {
destFilePath = destFilePath + File.separator;
}
FileUtil.makeFilePath(destFilePath, false);
String yamlFilePath = destFilePath + "docker-compose-peer.yaml";
if (!yamlFileService.writeObjectToYamlFile(peerComposeConfig, yamlFilePath)) {
return false;
}
// 生成 start-peer.sh
/*String content = getFileContent(workingDir + "template/start-peer.sh");
String newFilePath = destFilePath + "start-peer.sh";
if (!writeFileContent(newFilePath, content)) {
return false;
}*/
String newShFilePath = destFilePath + "start-peer.sh";
String srcShFilePat = modeService.getInitDir() + "template/start-peer.sh";
FileUtils.copyFile(new File(srcShFilePat), new File(newShFilePath));
return true;
}
}

View file

@ -0,0 +1,340 @@
package com.cgb.bcpinstall.service;
import com.alibaba.fastjson.JSON;
import com.cgb.bcpinstall.common.entity.OSEnum;
import com.cgb.bcpinstall.common.entity.RoleEnum;
import com.cgb.bcpinstall.common.entity.UpdateReasonEnum;
import com.cgb.bcpinstall.common.entity.init.InitConfigEntity;
import com.cgb.bcpinstall.common.util.FileUtil;
import com.cgb.bcpinstall.common.util.NetUtil;
import com.cgb.bcpinstall.common.util.Utils;
import com.cgb.bcpinstall.config.GlobalConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.yaml.snakeyaml.Yaml;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* 文件服务类
*
* @author zheng.li
* @date 2020/3/2 14:54
*/
@Service
@Slf4j
public class FileService {
private static final String CERTS_FOLDER_NAME = "crypto-config";
@Autowired
private ModeService modeService;
@Autowired
protected GlobalConfig globalConfig;
@Value("${init.config}")
protected String initConfigFile;
/**
* 将需要的文件复制到安装目录
*
* @param ipList
* @param roleList
* @return
*/
public void copyInstallFiles(List<String> ipList, List<RoleEnum> roleList, InitConfigEntity configEntity) {
// 如果master节点不担任任何角色则返回空
if (roleList.isEmpty()) {
return;
}
for (RoleEnum role : roleList) {
for (String ip : ipList) {
copyFiles(role, ip, modeService.getInstallPath(), configEntity);
}
}
}
public void copyFiles(RoleEnum role, String ip, String destPath, InitConfigEntity configEntity) {
copyFiles(role, ip, null, destPath, null, configEntity, null);
}
/**
* 将相应角色的文件复制到指定路径
*
* @param role
* @param ip
* @param srcFolderName
* @param destPath
*/
public void copyFiles(RoleEnum role, String ip, String srcFolderName, String destPath, String destFolderName, InitConfigEntity configEntity, List<String> hostArray) {
FileUtil.makeFilePath(destPath, false);
String srcRootPath = FileUtil.reviseDir(modeService.getInitDir());
try {
String dockerSrcFile = srcRootPath + "fabric-net" + File.separator + "dockerFile" + File.separator;
if (!destPath.endsWith(File.separator)) {
destPath = destPath + File.separator;
}
copyCertFiles(role, ip, destPath, configEntity);
switch (role) {
case ORDER:
String orderDir = dockerSrcFile + (StringUtils.isEmpty(srcFolderName) ? "order-" + ip : srcFolderName);
if (!new File(orderDir).exists()) {
log.info(String.format("目录 %s 不存在", orderDir));
break;
}
FileUtils.copyDirectory(new File(orderDir), new File(destPath + (StringUtils.isEmpty(destFolderName) ? "order" : destFolderName)));
// 需要复制创世块
if (NetUtil.getLocalIPList().stream().noneMatch(i -> i.equalsIgnoreCase(ip))) {
FileUtils.copyDirectory(new File(modeService.getInstallPath() + "channel-artifacts"), new File(destPath + "channel-artifacts"));
}
break;
case PEER:
String peerDir = dockerSrcFile + (StringUtils.isEmpty(srcFolderName) ? "peer-" + ip : srcFolderName);
if (!new File(peerDir).exists()) {
log.info(String.format("目录 %s 不存在", peerDir));
break;
}
FileUtils.copyDirectory(new File(peerDir), new File(destPath + (StringUtils.isEmpty(destFolderName) ? "peer" : destFolderName)));
break;
}
} catch (Exception e) {
log.error(String.format("为 %s 复制 %s 角色文件失败", ip, role.name()), e);
e.printStackTrace();
}
}
/**
* 复制相应的证书文件
*
* @param role
* @param ip
* @param destPath
*/
public void copyCertFiles(RoleEnum role, String ip, String destPath, InitConfigEntity configEntity) {
log.info(String.format("为服务器 %s 角色 %s 复制证书文件, 目标目录: %s", ip, role.name(), destPath));
if (!destPath.endsWith(File.separator)) {
destPath = destPath + File.separator;
}
String certRootPath = destPath + CERTS_FOLDER_NAME + File.separator;
FileUtil.makeFilePath(certRootPath, false);
String midDirName01;
String midDirName02;
Map<String, String> hostConfig;
if (role == RoleEnum.ORDER) {
hostConfig = configEntity.getOrdererHostConfig();
midDirName01 = "ordererOrganizations";
midDirName02 = "orderers";
} else {
hostConfig = configEntity.getPeerHostConfig();
midDirName01 = "peerOrganizations";
midDirName02 = "peers";
}
for (String domain : hostConfig.keySet()) {
String val = hostConfig.get(domain);
int index = val.lastIndexOf(":");
if (val.substring(0, index).endsWith(ip)) {
int i = domain.indexOf(".");
String relativePath = midDirName01 + File.separator + domain.substring(i + 1)
+ File.separator + midDirName02 + File.separator + domain;
String srcDir = modeService.getInitDir() + "fabric-net" + File.separator + "cryptoAndConfig" + File.separator + "crypto-config"
+ File.separator + relativePath;
try {
FileUtils.copyDirectory(new File(srcDir), new File(certRootPath + relativePath));
} catch (IOException e) {
log.error(String.format("复制%s证书文件异常", role.name()), e);
e.printStackTrace();
}
}
}
}
/**
* 将证书文件复制到主节点
*/
public void masterCopyCryptoConfig() {
String srcDir = modeService.getInitDir() + "fabric-net" + File.separator + "cryptoAndConfig" + File.separator + "crypto-config"
+ File.separator;
try {
FileUtils.copyDirectory(new File(srcDir), new File(modeService.getInstallPath() + "crypto-config"));
} catch (IOException e) {
log.error("主节点复制证书文件异常", e);
e.printStackTrace();
}
}
/**
* 将configtx.yaml文件复制到主节点
*/
public void masterCopyConfigtxFile() {
log.info("复制 configtx.yaml 文件到安装目录");
FileUtil.makeFilePath(modeService.getInstallPath(), false);
String srcRootPath = FileUtil.reviseDir(modeService.getInitDir());
String srcFile = srcRootPath + "fabric-net" + File.separator + "cryptoAndConfig" + File.separator + "configtx.yaml";
try {
log.info("生成创世快-从" + srcFile + "复制到" + modeService.getInstallPath() + "configtx.yaml");
FileUtils.copyFile(new File(srcFile), new File(modeService.getInstallPath() + "configtx.yaml"));
} catch (IOException e) {
log.error("复制 configtx.yaml 文件到安装目录异常", e);
e.printStackTrace();
}
}
/**
* 为机器打包智能安装包
*
* @param serverAddress 机器IP地址
* @param roleList 所充当的角色
* @return
*/
public String packInstallFiles(String serverAddress, List<RoleEnum> roleList, InitConfigEntity configEntity) {
log.info(String.format("为服务器 %s 准备智能安装包, 该服务器承担的角色:%s", serverAddress, roleList.stream().map(Enum::name).collect(Collectors.joining(","))));
if (configEntity == null) {
try {
Yaml yaml = new Yaml();
configEntity = yaml.loadAs(new FileInputStream(new File(this.initConfigFile)), InitConfigEntity.class);
} catch (Exception e) {
log.error("安装过程发生异常", e);
e.printStackTrace();
}
}
// 建一个临时目录
String tmpPath = System.getProperty("java.io.tmpdir");
if (!tmpPath.endsWith(File.separator)) {
tmpPath = tmpPath + File.separator;
}
String rootPath = tmpPath + UUID.randomUUID().toString().replaceAll("-", "") + File.separator;
String packSrcPath = rootPath + "installFiles" + File.separator;
FileUtil.makeFilePath(packSrcPath, true);
for (RoleEnum role : roleList) {
this.copyFiles(role, serverAddress, packSrcPath, configEntity);
}
// 打包
try {
String packFilePath = rootPath + "InstallPackage.tar.gz";
byte[] data = Utils.generateTarGz(new File(packSrcPath), "", null);
FileOutputStream os = new FileOutputStream(packFilePath, false);
os.write(data);
os.close();
FileUtil.rmFile(new File(packSrcPath));
return packFilePath;
} catch (IOException e) {
log.error("生成智能安装包时异常", e);
e.printStackTrace();
}
return "";
}
/**
* 为扩容节点打包所需安装文件
*
* @param serverAddress
* @param folderName
* @param roleEnum
* @param configEntity
* @return
*/
public String packExtendNodeFiles(String serverAddress, String folderName, RoleEnum roleEnum, InitConfigEntity configEntity) {
String role = "";
switch (roleEnum) {
case PEER:
role = "peer";
break;
case ORDER:
role = "orderer";
break;
}
log.info(String.format("为新 %s 节点 %s 准备智能安装包", role, serverAddress));
// 建一个临时目录
String tmpPath = System.getProperty("java.io.tmpdir");
if (!tmpPath.endsWith(File.separator)) {
tmpPath = tmpPath + File.separator;
}
String rootPath = tmpPath + UUID.randomUUID().toString().replaceAll("-", "") + File.separator;
String packSrcPath = rootPath + "installFiles" + File.separator;
FileUtil.makeFilePath(packSrcPath, true);
this.copyFiles(roleEnum, serverAddress, folderName, packSrcPath, folderName, configEntity, null);
// 打包
try {
String packFilePath = rootPath + "InstallPackage.tar.gz";
byte[] data = Utils.generateTarGz(new File(packSrcPath), "", null);
FileOutputStream os = new FileOutputStream(packFilePath, false);
os.write(data);
os.close();
FileUtil.rmFile(new File(packSrcPath));
return packFilePath;
} catch (IOException e) {
log.error("生成智能安装包时异常", e);
e.printStackTrace();
}
return "";
}
/**
* 移除证书
*
* @param role
* @param configEntity
* @param nodeHostMap
* @param isInitDir
*/
public void removeCertFile(RoleEnum role, InitConfigEntity configEntity, Map<String, String> nodeHostMap, boolean isInitDir) {
for (String nodeHost : nodeHostMap.keySet()) {
String cryptoFilePath = "crypto-config" + File.separator + "%s" + File.separator + "%s" + File.separator + "%s" + File.separator + "%s";
String peerCertPath = String.format(cryptoFilePath, "peerOrganizations", configEntity.getPeerDomain(), "peers", nodeHost);
String ordererCertPath = String.format(cryptoFilePath, "ordererOrganizations", configEntity.getOrdererDomain(), "orderers", nodeHost);
String rmPath;
if (role == RoleEnum.PEER) {
if (isInitDir) {
rmPath = modeService.getInitDir() + "fabric-net" + File.separator + "cryptoAndConfig" + File.separator + peerCertPath;
} else {
rmPath = modeService.getInstallPath() + peerCertPath;
}
} else {
if (isInitDir) {
rmPath = modeService.getInitDir() + "fabric-net" + File.separator + "cryptoAndConfig" + File.separator + ordererCertPath;
} else {
rmPath = modeService.getInstallPath() + ordererCertPath;
}
}
log.info("缩容节点,移除证书路径:" + rmPath);
FileUtil.rmFile(new File(rmPath));
}
}
}

View file

@ -0,0 +1,146 @@
package com.cgb.bcpinstall.service;
import com.cgb.bcpinstall.common.entity.init.InitConfigEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.yaml.snakeyaml.Yaml;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Collection;
import java.util.Map;
/**
* 配置信息服务类
*
* @author zheng.li
* @date 2020/3/9 10:26
*/
@Slf4j
@Service
public class InitConfigService {
/**
* 根据配置文件路径获取配置信息
*
* @param filePath
* @return
* @throws FileNotFoundException
*/
public InitConfigEntity parseConfigFile(String filePath) throws FileNotFoundException {
File file = new File(filePath);
if (!file.exists() && !file.isFile()) {
throw new FileNotFoundException(filePath);
}
InitConfigEntity initConfigEntity = null;
Yaml yaml = new Yaml();
try {
initConfigEntity = yaml.loadAs(new FileInputStream(file), InitConfigEntity.class);
} catch (Exception e) {
log.error("配置文件读取异常,请检查各配置项是否符合格式要求");
}
return initConfigEntity;
}
public boolean isCorrectConfig(InitConfigEntity initConfigEntity) {
boolean isCorrect = true;
if (!isNotEmptyConfig(initConfigEntity)) {
log.error("配置文件中相关配置项为空");
isCorrect = false;
}
if (!isCorrectFormat(initConfigEntity)) {
log.error("配置文件中相关域名的ip和端口格式不正确");
isCorrect = false;
}
if (!isCorrectDomain(initConfigEntity)) {
log.error("配置文件中orderer或peer的域名不匹配");
isCorrect = false;
}
if (!checkPeerConfig(initConfigEntity)) {
log.error("配置文件中peer没有配置相应的交易查询端口");
isCorrect = false;
}
return isCorrect;
}
/**
* 检查orderer与peer域名是否匹配
*
* @param initConfigEntity
* @return
*/
private boolean isCorrectDomain(InitConfigEntity initConfigEntity) {
String ordererDomain = initConfigEntity.getOrdererDomain();
String peerDomain = initConfigEntity.getPeerDomain();
boolean peerMatch = initConfigEntity.getPeerHostConfig().keySet().stream().allMatch(i -> i.endsWith(peerDomain));
boolean ordererMatch = initConfigEntity.getOrdererHostConfig().keySet().stream().allMatch(i -> i.endsWith(ordererDomain));
return peerMatch && ordererMatch;
}
private boolean checkPeerConfig(InitConfigEntity configEntity) {
boolean isCorrect = true;
Map<String, String> peerConfigMap = configEntity.getPeerHostConfig();
Map<String, String> peerMetricConfigMap = configEntity.getMetricPortConfig();
for (String host : peerConfigMap.keySet()) {
if (peerMetricConfigMap.keySet().stream().noneMatch(i -> i.equals(host))) {
isCorrect = false;
}
}
return isCorrect;
}
private boolean isNotEmptyConfig(InitConfigEntity configEntity) {
boolean isCorrect = true;
if (StringUtils.isEmpty(configEntity.getNetwork())
|| StringUtils.isEmpty(configEntity.getChannelName())
|| StringUtils.isEmpty(configEntity.getOrgMSPID())
|| StringUtils.isEmpty(configEntity.getOrgName())
|| StringUtils.isEmpty(configEntity.getOrdererDomain())
|| StringUtils.isEmpty(configEntity.getPeerDomain())) {
isCorrect = false;
}
if (CollectionUtils.isEmpty(configEntity.getOrdererHostConfig())
|| CollectionUtils.isEmpty(configEntity.getPeerHostConfig())
|| CollectionUtils.isEmpty(configEntity.getMetricPortConfig())) {
isCorrect = false;
}
if (configEntity.getOrdererHostConfig().entrySet().stream().anyMatch(i -> StringUtils.isEmpty(i.getValue()))) {
isCorrect = false;
}
if (configEntity.getPeerHostConfig().entrySet().stream().anyMatch(i -> StringUtils.isEmpty(i.getValue()))) {
isCorrect = false;
}
if (configEntity.getMetricPortConfig().entrySet().stream().anyMatch(i -> StringUtils.isEmpty(i.getValue()))) {
isCorrect = false;
}
return isCorrect;
}
private boolean isCorrectFormat(InitConfigEntity configEntity) {
Collection<String> peerIpPorts = configEntity.getPeerHostConfig().values();
if (!isCorrectFormat(peerIpPorts)) {
return false;
}
Collection<String> ordererIpPorts = configEntity.getOrdererHostConfig().values();
return isCorrectFormat(ordererIpPorts);
}
private boolean isCorrectFormat(Collection<String> ipPorts) {
for (String ipPort : ipPorts) {
if (ipPort.split(":").length != 2) {
return false;
}
}
return true;
}
}

View file

@ -0,0 +1,198 @@
package com.cgb.bcpinstall.service;
import com.cgb.bcpinstall.biz.RolesBiz;
import com.cgb.bcpinstall.common.entity.InstallResult;
import com.cgb.bcpinstall.common.entity.InstallStatusEnum;
import com.cgb.bcpinstall.common.entity.RoleEnum;
import com.cgb.bcpinstall.common.entity.ServerEntity;
import com.cgb.bcpinstall.common.entity.init.InitConfigEntity;
import com.cgb.bcpinstall.common.response.HttpInstallResponse;
import com.cgb.bcpinstall.common.response.ResponseCode;
import com.cgb.bcpinstall.common.util.FileUtil;
import com.cgb.bcpinstall.common.util.NetUtil;
import com.cgb.bcpinstall.common.util.ProcessUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.yaml.snakeyaml.Yaml;
import java.io.File;
import java.io.FileInputStream;
import java.util.List;
import java.util.Map;
/**
* 安装服务类
*
* @author zheng.li
* @date 2020/3/2 14:55
*/
@Service
@Slf4j
public class InstallService {
@Autowired
private ModeService modeService;
@Autowired
private EnvironmentService environmentService;
@Autowired
private RemoteService remoteService;
@Autowired
protected RolesBiz rolesBiz;
@Value("${init.config}")
protected String initConfigFile;
/**
* 主节点调用用来进行相应角色的安装如果主节点担任相应角色则启动本地安装否则发送安装指令给从节点
*
* @param role
*/
public void install(RoleEnum role, InitConfigEntity configEntity) {
List<String> allMyIps = NetUtil.getLocalIPList();
Map<RoleEnum, List<ServerEntity>> rolesMap = this.rolesBiz.getRolesMap();
List<ServerEntity> serverList = rolesMap.get(role);
boolean first = true;
for (ServerEntity server : serverList) {
if (server.getStatus() != InstallStatusEnum.SUCCESS) {
// 如果主节点也是此角色则先安装
int initCount = 1;
if (allMyIps.stream().anyMatch(ip -> ip.equals(server.getHost()))) {
Map<String, String> hosts = environmentService.getRoleNeedSetHost(role, configEntity);
if (startRole(role, server.getRolePorts(), hosts, null)) {
server.setStatus(InstallStatusEnum.SUCCESS);
}
InstallResult result = new InstallResult();
result.setRole(server.getRole());
result.setSuccess(true);
updateInstallResult(server.getHost(), result, configEntity);
} else {
//设置重试次数初始化值
int retryCount = 1;
//设置重试次数
int retryTotal = 10;
// 发送安装指令给从节点
do {
HttpInstallResponse response = remoteService.sendInstallCommand(server, role, null, configEntity);
if (ResponseCode.SUCCESS.getCode().equals(response.getCode())) {
log.warn(String.format("发送安装指令给 %s 节点安装 %s 成功", server.getHost(), role.name().toLowerCase()));
server.setStatus(InstallStatusEnum.INSTALLING);
break;
}
if (retryCount == retryTotal) {
break;
}
log.warn(String.format("发送安装指令给 %s 节点安装 %s 失败,稍后重试...", server.getHost(), role.name().toLowerCase()));
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
retryCount++;
} while (true);
}
}
}
// 等待完成安装
int checkCount = 1;
int checkTotal = 10;
while (serverList.stream().anyMatch(s -> s.getStatus() != InstallStatusEnum.SUCCESS)) {
if (checkCount == checkTotal) {
break;
}
log.info(String.format("等待所有 %s 节点完成安装...", role.name().toLowerCase()));
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
checkCount++;
}
}
public boolean startRole(RoleEnum role, List<String> rolePorts, Map<String, String> hosts, String roleFolderName) {
return startRole(role, rolePorts, hosts, roleFolderName, null);
}
/**
* 执行角色相应的脚本
*
* @param role
*/
public boolean startRole(RoleEnum role, List<String> rolePorts, Map<String, String> hosts, String roleFolderName, String host) {
log.info(String.format("开始执行角色 %s 的脚本", role.name()));
if (!new File(modeService.getInstallPath()).exists()) {
FileUtil.makeFilePath(modeService.getInstallPath(), false);
}
String[] env = null;
String shellFilePath = null;
String workingDir = null;
switch (role) {
case ORDER:
workingDir = modeService.getInstallPath() + (StringUtils.isEmpty(roleFolderName) ? "order" : roleFolderName);
shellFilePath = modeService.getInstallPath() + (StringUtils.isEmpty(roleFolderName) ? "order" : roleFolderName) + "/start-orderer.sh up";
break;
case PEER:
workingDir = modeService.getInstallPath() + (StringUtils.isEmpty(roleFolderName) ? "peer" : roleFolderName);
shellFilePath = modeService.getInstallPath() + (StringUtils.isEmpty(roleFolderName) ? "peer" : roleFolderName) + "/start-peer.sh up";
break;
}
if (!StringUtils.isEmpty(shellFilePath)) {
environmentService.envSet(rolePorts, hosts);
try {
ProcessUtil.Result res = ProcessUtil.execCmd("bash " + shellFilePath, env, workingDir);
return res.getCode() == 0;
} catch (Exception e) {
log.error(String.format("启动角色%s脚本异常", role.name()), e);
e.printStackTrace();
}
}
return false;
}
/**
* 更新从节点安装结果
*
* @param remoteAddress
* @param result
*/
public void updateInstallResult(String remoteAddress, InstallResult result, InitConfigEntity configEntity) {
if (configEntity == null) {
File configFile = new File(this.initConfigFile);
Yaml yaml = new Yaml();
try {
configEntity = yaml.loadAs(new FileInputStream(configFile), InitConfigEntity.class);
} catch (Exception e) {
e.printStackTrace();
return;
}
}
if (result.isSuccess()) {
log.info(String.format("节点 %s 已完成 %s 角色的安装", remoteAddress, result.getRole().name()));
// 加入数据库
switch (result.getRole()) {
case ORDER:
modeService.checkAndInsertDb(configEntity.getOrdererHostConfig(), remoteAddress, RoleEnum.ORDER, configEntity.getOrgMSPID());
break;
case PEER:
modeService.checkAndInsertDb(configEntity.getPeerHostConfig(), remoteAddress, RoleEnum.PEER, configEntity.getOrgMSPID());
break;
}
}
this.rolesBiz.updateInstallResult(remoteAddress, result);
}
}

View file

@ -0,0 +1,136 @@
package com.cgb.bcpinstall.service;
import com.cgb.bcpinstall.biz.RolesBiz;
import com.cgb.bcpinstall.common.entity.*;
import com.cgb.bcpinstall.common.entity.init.InitConfigEntity;
import com.cgb.bcpinstall.common.response.HttpInstallResponse;
import com.cgb.bcpinstall.common.response.ResponseCode;
import com.cgb.bcpinstall.common.util.*;
import com.cgb.bcpinstall.db.CheckPointDb;
import com.cgb.bcpinstall.db.table.NodeDO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.yaml.snakeyaml.Yaml;
import java.io.*;
import java.sql.SQLException;
import java.util.*;
/**
* @author zheng.li
* @date 2020/2/3 14:26
*/
@Service
@Slf4j
public class ModeService {
@Autowired
protected RolesBiz rolesBiz;
@Autowired
protected CheckPointDb checkPointDb;
@Value("${init.config}")
protected String initConfigFile;
@Value("${init.dir}")
protected String initDir;
@Value("${install.path}")
protected String installPath;
public HttpInstallResponse createFailedHttpResponse() {
HttpInstallResponse response = new HttpInstallResponse();
response.setCode(ResponseCode.Fail.getCode());
return response;
}
/**
* @return true -- 初始化完成
*/
public boolean checkBackendInitFinished(String host, String shPath) {
String logFilePath = this.getInstallPath() + "bcp-app-mgr-" + host + File.separator + "log.out";
try {
ProcessUtil.Result result = ProcessUtil.execCmd("sh ./fetchBackendInit.sh " + logFilePath, null, shPath);
log.info(StringUtils.isEmpty(result.getData()) ? "后台初始化中,请耐心等待............" : "后台初始化成功");
return !StringUtils.isEmpty(result.getData());
} catch (Exception e) {
log.error("查询管理后台日志异常", e);
e.printStackTrace();
}
return false;
}
/**
* 更新从节点安装结果
*
* @param remoteAddress
* @param result
*/
public void updateInstallResult(String remoteAddress, InstallResult result, InitConfigEntity configEntity) {
if (configEntity == null) {
File configFile = new File(this.initConfigFile);
Yaml yaml = new Yaml();
try {
configEntity = yaml.loadAs(new FileInputStream(configFile), InitConfigEntity.class);
} catch (Exception e) {
e.printStackTrace();
return;
}
}
if (result.isSuccess()) {
log.info(String.format("节点 %s 已完成 %s 角色的安装", remoteAddress, result.getRole().name()));
// 加入数据库
switch (result.getRole()) {
case ORDER:
checkAndInsertDb(configEntity.getOrdererHostConfig(), remoteAddress, RoleEnum.ORDER, configEntity.getOrgMSPID());
break;
case PEER:
checkAndInsertDb(configEntity.getPeerHostConfig(), remoteAddress, RoleEnum.PEER, configEntity.getOrgMSPID());
break;
}
}
this.rolesBiz.updateInstallResult(remoteAddress, result);
}
public void checkAndInsertDb(Map<String, String> hostConfig, String ip, RoleEnum role, String orgMspId) {
for (String host : hostConfig.keySet()) {
String hIp = hostConfig.get(host);
int index = hIp.lastIndexOf(":");
String port = hIp.substring(index + 1);
hIp = hIp.substring(0, index);
if (hIp.equalsIgnoreCase(ip)) {
NodeDO nodeDO = new NodeDO();
nodeDO.setOrgMspId(orgMspId);
nodeDO.setRole(role);
nodeDO.setHostName(host);
nodeDO.setIp(ip);
nodeDO.setPort(Integer.parseInt(port));
nodeDO.setStatus(InstallStatusEnum.SUCCESS);
try {
this.checkPointDb.addNodeRecord(nodeDO);
} catch (SQLException e) {
log.error(String.format("添加节点 %s 角色 %s 到数据库失败", ip, role.name().toLowerCase()), e);
e.printStackTrace();
}
}
}
}
public String getInitDir() {
return this.initDir.endsWith(File.separator) ? this.initDir : this.initDir + File.separator;
}
public String getInstallPath() {
String installPath = this.installPath.endsWith(File.separator) ? this.installPath : this.installPath + File.separator;
return installPath;
}
}

View file

@ -0,0 +1,171 @@
package com.cgb.bcpinstall.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cgb.bcpinstall.biz.RolesBiz;
import com.cgb.bcpinstall.common.entity.*;
import com.cgb.bcpinstall.common.entity.init.InitConfigEntity;
import com.cgb.bcpinstall.common.response.HttpInstallResponse;
import com.cgb.bcpinstall.common.response.ResponseCode;
import com.cgb.bcpinstall.common.util.HttpClientUtil;
import com.cgb.bcpinstall.common.util.NetUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.util.*;
/**
* 远程调用服务类
*
* @author zheng.li
* @date 2020/3/2 14:58
*/
@Service
@Slf4j
public class RemoteService {
@Autowired
private ModeService modeService;
@Autowired
private EnvironmentService environmentService;
@Autowired
private FileService fileService;
@Autowired
protected HttpClientUtil httpClient;
@Autowired
protected RolesBiz rolesBiz;
/**
* 主节点给从节点发送安装指令
*
* @param server
* @param role
* @return
*/
public HttpInstallResponse sendInstallCommand(ServerEntity server, RoleEnum role, String folderName, InitConfigEntity configEntity) {
log.info(String.format("主节点给从节点 %s 发送安装角色:%s", server.getHost(), role.name()));
try {
Map<String, String> revisedHosts = new HashMap<>();
Map<String, String> hosts = environmentService.getRoleNeedSetHost(role, configEntity);
for (String h : hosts.keySet()) {
String ip = hosts.get(h);
if ("127.0.0.1".equalsIgnoreCase(ip)) {
revisedHosts.put(h, NetUtil.getMyNormalIP());
} else {
revisedHosts.put(h, ip);
}
}
//设置从节点安装信息实例
InstallCmd entity = new InstallCmd();
entity.setHosts(revisedHosts);
entity.setIpAddress(server.getHost());
entity.setRole(role);
entity.setRolePorts(server.getRolePorts());
entity.setRoleFolderName(folderName);
//发生安装指令
String result = this.httpClient.sendFileAndJson(server.getHttpUrl() + "/v1/install/start", "", JSONObject.toJSONString(entity));
if (result.isEmpty()) {
log.error("注册角色返回结果为空");
} else {
log.info("注册角色返回结果: " + result);
return JSON.parseObject(result, HttpInstallResponse.class);
}
} catch (Exception e) {
log.error("发送安装指令异常", e);
e.printStackTrace();
}
return modeService.createFailedHttpResponse();
}
/**
* 向从节点推送安装包
*
* @param remoteAddr
* @param configEntity
*/
public void pushSlaveInstallPackage(String remoteAddr, InitConfigEntity configEntity) {
pushSlaveInstallPackage(remoteAddr, null, configEntity);
}
public void pushSlaveInstallPackage(String remoteAddr, String packFilePath, InitConfigEntity configEntity) {
List<RoleEnum> roleList = this.rolesBiz.getRole(remoteAddr);
String filePath = StringUtils.isEmpty(packFilePath) ? fileService.packInstallFiles(remoteAddr, roleList, configEntity) : packFilePath;
//重试次数初始化为1
int retryCount = 1;
//设置重试次数
int retryTotal = 8;
do {
String result = httpClient.uploadFile("http://" + remoteAddr + ":8080/v1/install/pushPackage", filePath);
if (!StringUtils.isEmpty(result)) {
HttpInstallResponse response = JSONObject.parseObject(result, HttpInstallResponse.class);
if (ResponseCode.SUCCESS.getCode().equals(response.getCode())) {
log.info(String.format("向从节点 %s 推送安装包成功", remoteAddr));
this.rolesBiz.setServerStatus(remoteAddr, InstallStatusEnum.DOWNLOADED);
break;
}
}
if (retryCount == retryTotal) {
break;
}
log.info(String.format("向从节点 %s 推送安装包失败,稍后重试...", remoteAddr));
try {
Thread.sleep(8000);
} catch (Exception e) {
e.printStackTrace();
}
retryCount++;
} while (true);
}
/**
* 通知节点安装完成结束
*
* @param serverUrl
*/
public void notifyNodesToEnd(Set<String> serverUrl) {
for (String url : serverUrl) {
if (!url.endsWith("/")) {
url = url + "/";
}
EndCmd cmd = new EndCmd();
cmd.setSuccess(true);
try {
int retryCount = 1;
int retryTotal = 7;
do {
String result = this.httpClient.postJson(url + "v1/install/end", JSONObject.toJSONString(cmd), false);
if (!StringUtils.isEmpty(result)) {
HttpInstallResponse response = JSONObject.parseObject(result, HttpInstallResponse.class);
if (ResponseCode.SUCCESS.getCode().equals(response.getCode())) {
log.info(String.format("发送结束指令给 %s 成功", url));
break;
}
}
if (retryCount == retryTotal) {
log.info("发送结束指令超时");
break;
}
log.info(String.format("发送结束指令给 %s 失败,稍后重试...", url));
try {
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
}
retryCount++;
} while (true);
} catch (IOException e) {
log.error(String.format("发送结束指令给 %s 异常", url));
e.printStackTrace();
}
}
}
}

View file

@ -0,0 +1,90 @@
package com.cgb.bcpinstall.service;
import com.cgb.bcpinstall.biz.RolesBiz;
import com.cgb.bcpinstall.common.entity.RoleEnum;
import com.cgb.bcpinstall.common.entity.init.InitConfigEntity;
import com.cgb.bcpinstall.common.util.HttpClientUtil;
import com.cgb.bcpinstall.config.GlobalConfig;
import com.cgb.bcpinstall.db.CheckPointDb;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 角色服务类
*
* @author zheng.li
* @date 2020/3/2 15:20
*/
@Service
@Slf4j
public class RoleService {
@Autowired
protected RolesBiz rolesBiz;
@Autowired
protected GlobalConfig globalConfig;
/**
* 根据服务器IP地址解析其所担任的角色并添加到RoleBiz中
*
* @param remoteAddr 服务器IP地址
* @param serverHttpPort 服务器HTTP服务的端口
*/
public void addServerRole(String remoteAddr, String serverHttpPort, InitConfigEntity configEntity) {
Map<RoleEnum, List<String>> roles = parseAllRoles(remoteAddr, configEntity);
for (RoleEnum role : roles.keySet()) {
List<String> ports = roles.get(role);
this.rolesBiz.addRole(role, "http://" + remoteAddr + ":" + serverHttpPort, remoteAddr, ports);
}
}
/**
* 根据配置文件和远程从节点的IP地址获取其角色
* 注意一台服务器可以有多个角色
*
* @param slaveAddress
* @return 返回 RoleEnum->端口列表
*/
public Map<RoleEnum, List<String>> parseAllRoles(String slaveAddress, InitConfigEntity configEntity) {
log.info(String.format("为服务器 %s 解析角色", slaveAddress));
Map<RoleEnum, List<String>> roles = new HashMap<>(16);
this.parseRole(roles, slaveAddress, configEntity.getOrdererHostConfig(), RoleEnum.ORDER, configEntity);
this.parseRole(roles, slaveAddress, configEntity.getPeerHostConfig(), RoleEnum.PEER, configEntity);
log.info(String.format("服务器 %s 解析后,所承担的角色有: ", slaveAddress, roles.keySet().stream().map(Enum::name).collect(Collectors.joining(","))));
return roles;
}
private void parseRole(Map<RoleEnum, List<String>> roles, String slaveAddress, Map<String, String> hostConfig, RoleEnum role, InitConfigEntity configEntity) {
for (String host : hostConfig.keySet()) {
String ip = hostConfig.get(host);
int index = ip.lastIndexOf(":");
String port = ip.substring(index + 1);
ip = ip.substring(0, index);
if (slaveAddress.equals(ip)) {
List<String> ports;
if (roles.containsKey(role)) {
ports = roles.get(role);
} else {
ports = new ArrayList<>();
roles.put(role, ports);
}
if (ports.stream().noneMatch(p -> p.equalsIgnoreCase(port))) {
ports.add(port);
}
}
}
}
}

View file

@ -0,0 +1,199 @@
package com.cgb.bcpinstall.service;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cgb.bcpinstall.common.entity.RemoveCmd;
import com.cgb.bcpinstall.common.entity.RoleEnum;
import com.cgb.bcpinstall.common.entity.init.InitConfigEntity;
import com.cgb.bcpinstall.common.util.*;
import com.cgb.bcpinstall.config.GlobalConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.io.File;
import java.io.IOException;
import java.util.*;
/**
* 扩缩容节点的服务类
*
* @author zheng.li
* @date 2020/3/2 15:36
*/
@Service
@Slf4j
public class UpdateService {
@Autowired
private ModeService modeService;
@Autowired
private EnvironmentService environmentService;
@Autowired
protected HttpClientUtil httpClient;
@Autowired
protected GlobalConfig globalConfig;
/**
* 根据添加的新节点与最新的节点配置返回更新前的原节点配置
*
* @param currentConfig
* @param newConfig
* @return
*/
public Map<String, String> getOldNodeConfigMap(Map<String, String> currentConfig, Map<String, String> newConfig) {
if (CollectionUtils.isEmpty(currentConfig) && CollectionUtils.isEmpty(newConfig)) {
return new HashMap<>(16);
}
newConfig.keySet().forEach(currentConfig::remove);
return currentConfig;
}
public RemoveCmd createRemoveCmd(String ip, List<String> ipPorts, RoleEnum role) {
RemoveCmd removeCmd = new RemoveCmd();
List<String> hosts = new ArrayList<>();
List<String> ports = new ArrayList<>();
removeCmd.setIp(ip);
removeCmd.setRole(role);
for (String ipPort : ipPorts) {
String[] ipPortSplit = ipPort.split(":");
if (ipPortSplit.length != 2) {
return null;
}
hosts.add(ipPortSplit[0]);
ports.add(ipPortSplit[1]);
}
removeCmd.setHostNames(hosts);
removeCmd.setPorts(ports);
return removeCmd;
}
/**
* 更新 fabric 网络配置
*
* @param channelName
* @param configEntity
* @return
*/
public boolean updateNetworkConfig(String channelName, InitConfigEntity configEntity, Map<String, String> ordererConfigMap) {
FileUtil.makeFilePath(modeService.getInstallPath() + "cli/scripts", false);
try {
FileUtils.copyFile(new File(modeService.getInitDir() + "template/fetch-config.sh"), new File(modeService.getInstallPath() + "cli/scripts/fetch-config.sh"));
FileUtils.copyFile(new File(modeService.getInitDir() + "template/create-update-pb.sh"), new File(modeService.getInstallPath() + "cli/scripts/create-update-pb.sh"));
FileUtils.copyFile(new File(modeService.getInitDir() + "template/update-channel-config.sh"), new File(modeService.getInstallPath() + "cli/scripts/update-channel-config.sh"));
} catch (IOException e) {
log.error("复制脚本文件异常", e);
e.printStackTrace();
return false;
}
// 获取通道配置信息
String firstOrdererHost = configEntity.getOrdererHostConfig().keySet().iterator().next();
String ip = configEntity.getOrdererHostConfig().get(firstOrdererHost);
String firstOrdererHostAddress = firstOrdererHost + ip.substring(ip.lastIndexOf(":"));
String CHANNEL_NAME = channelName;
String ORDERER_CA = String.format("/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/%s/orderers/%s/msp/tlscacerts/tlsca.%s-cert.pem", configEntity.getOrdererDomain(), firstOrdererHost, configEntity.getOrdererDomain());
String CORE_PEER_LOCALMSPID = "OrdererMSP";
String CORE_PEER_ADDRESS = firstOrdererHostAddress;
String CORE_PEER_TLS_ROOTCERT_FILE = String.format("/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/%s/orderers/%s/tls/ca.crt", configEntity.getOrdererDomain(), firstOrdererHost);
String CORE_PEER_MSPCONFIGPATH = String.format("/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/%s/users/Admin@%s/msp", configEntity.getOrdererDomain(), configEntity.getOrdererDomain());
String cmd = "docker exec cli bash scripts/fetch-config.sh " + CHANNEL_NAME + " " + ORDERER_CA + " " + CORE_PEER_LOCALMSPID + " " + CORE_PEER_ADDRESS + " " + CORE_PEER_TLS_ROOTCERT_FILE + " " + CORE_PEER_MSPCONFIGPATH;
try {
ProcessUtil.execCmd(cmd, null, modeService.getInstallPath() + "cli");
} catch (Exception e) {
log.error(String.format("执行脚本获取通道 %s 配置异常", channelName), e);
e.printStackTrace();
return false;
}
// 修改通道配置: 增加 orderer 相关配置
String filePath = String.format("/var/run/config_%s.json", channelName);
if (!new File(filePath).exists()) {
log.error(String.format("通道 %s 配置文件 %s 不存在", channelName, filePath));
return false;
}
JSONObject jsonObject = JSONObject.parseObject(FileUtil.getFileContent(filePath));
JSONArray array = jsonObject.getJSONObject("channel_group").getJSONObject("groups").getJSONObject("Orderer").getJSONObject("values").getJSONObject("ConsensusType").getJSONObject("value").getJSONObject("metadata").getJSONArray("consenters");
JSONArray ordererAddresses = jsonObject.getJSONObject("channel_group").getJSONObject("values").getJSONObject("OrdererAddresses").getJSONObject("value").getJSONArray("addresses");
array.clear();
ordererAddresses.clear();
for (String oHost : ordererConfigMap.keySet()) {
String oIp = ordererConfigMap.get(oHost);
String certFilePath = modeService.getInstallPath() + "crypto-config/ordererOrganizations/" + configEntity.getOrdererDomain() + "/orderers/" + oHost + "/tls/server.crt";
if (!new File(certFilePath).exists()) {
log.error(String.format("orderer %s 的证书文件 %s 不存在", oHost, certFilePath));
return false;
}
String content = FileUtil.getFileContent(certFilePath);
String certStr = new String(Base64.getEncoder().encode(content.getBytes()));
JSONObject newOrdererObject = new JSONObject();
newOrdererObject.put("client_tls_cert", certStr);
newOrdererObject.put("host", oHost);
newOrdererObject.put("port", oIp.substring(oIp.lastIndexOf(":") + 1));
newOrdererObject.put("server_tls_cert", certStr);
String ordererAddr = oHost + ":" + oIp.substring(oIp.lastIndexOf(":") + 1);
array.add(newOrdererObject);
ordererAddresses.add(ordererAddr);
}
File modifiedFile = new File(String.format("/var/run/config_%s_modified.json", channelName));
FileUtil.writeTxtFile(jsonObject.toJSONString(), modifiedFile, "UTF-8");
if (!modifiedFile.exists()) {
log.error(String.format("创建通道 %s 配置编辑文件 %s 失败", channelName, modifiedFile.getAbsolutePath()));
return false;
}
// 创建 pb 文件
cmd = "docker exec cli bash scripts/create-update-pb.sh " + CHANNEL_NAME;
try {
ProcessUtil.execCmd(cmd, null, "/var/run");
} catch (Exception e) {
log.error(String.format("为通道 %s 执行脚本生成pb文件异常", channelName), e);
e.printStackTrace();
return false;
}
// 更新通道
cmd = "docker exec cli bash scripts/update-channel-config.sh " + CHANNEL_NAME + " " + ORDERER_CA + " " + CORE_PEER_LOCALMSPID + " " + CORE_PEER_ADDRESS + " " + CORE_PEER_TLS_ROOTCERT_FILE + " " + CORE_PEER_MSPCONFIGPATH;
try {
ProcessUtil.execCmd(cmd, null, modeService.getInstallPath() + "cli");
} catch (Exception e) {
log.error(String.format("为通道 %s 执行脚本更新网络配置异常", channelName), e);
e.printStackTrace();
}
return true;
}
public boolean removeNode(RoleEnum role, String domain, List<String> hostNames, List<String> ports) {
if (!CollectionUtils.isEmpty(ports)) {
ports.forEach(environmentService::removePortFromFirewall);
}
for (String host : hostNames) {
try {
log.info("移除节点容器sh stopNode.sh " + host.split(domain)[0]);
ProcessUtil.execCmd("sh stopNode.sh " + host.split(domain)[0], null, modeService.getInstallPath());
String roleFileName = role == RoleEnum.ORDER ? "ordererOrganizations" : "peerOrganizations";
String nodeFileName = role == RoleEnum.ORDER ? "orderers" : "peers";
String rmCertFile = String.format("crypto-config" + File.separator + "%s" + File.separator + "%s" + File.separator + "%s" + File.separator + "%s", roleFileName, domain, nodeFileName, host);
log.info("移除节点容器证书,路径:" + modeService.getInstallPath() + rmCertFile);
FileUtil.rmFile(new File(modeService.getInstallPath() + rmCertFile));
} catch (Exception e) {
log.error(String.format("移除节点 %s 异常", host), e);
e.printStackTrace();
}
}
return true;
}
}

View file

@ -0,0 +1,63 @@
package com.cgb.bcpinstall.service;
import com.cgb.bcpinstall.biz.helper.YamlRepresenter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.Map;
/**
* @author zheng.li
* @date 2020/3/12 15:54
*/
@Service
@Slf4j
public class YamlFileService {
DumperOptions createOption() {
DumperOptions dumperOptions = new DumperOptions();
dumperOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
dumperOptions.setDefaultScalarStyle(DumperOptions.ScalarStyle.PLAIN);
dumperOptions.setPrettyFlow(false);
return dumperOptions;
}
/**
* 将配置信息写入到yaml文件中
*
* @param entity
* @param yamlFile
* @return
*/
public boolean writeObjectToYamlFile(Map<Object, Object> entity, String yamlFile) {
DumperOptions options = this.createOption();
String yaml = new Yaml(new YamlRepresenter(options)).dumpAs(entity, null, DumperOptions.FlowStyle.BLOCK);
try {
File file = new File(yamlFile);
if (!file.getParentFile().exists()) {
boolean isMk = file.getParentFile().mkdirs();
if (!isMk) {
return false;
}
}
FileOutputStream outputStream = new FileOutputStream(file, false);
outputStream.write(yaml.getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
public Map<Object, Object> loadYamlFile(String filePath) throws FileNotFoundException {
return new Yaml().loadAs(new FileInputStream(new File(filePath)), Map.class);
}
}

View file

@ -0,0 +1,18 @@
{
"hints": [],
"groups": [
{
"sourceType": "com.cgb.bcpinstall.config.GlobalConfig",
"name": "global",
"type": "com.cgb.bcpinstall.config.GlobalConfig"
}
],
"properties": [
{
"sourceType": "com.cgb.bcpinstall.config.GlobalConfig",
"name": "global.master",
"description": "是否主节点",
"type": "java.lang.Integer"
}
]
}

View file

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="target/generated-sources/annotations">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View file

@ -0,0 +1,102 @@
<factorypath>
<factorypathentry kind="VARJAR" id="M2_REPO/commons-io/commons-io/1.3.2/commons-io-1.3.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/commons/commons-compress/1.18/commons-compress-1.18.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-web/2.0.6.RELEASE/spring-boot-starter-web-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter/2.0.6.RELEASE/spring-boot-starter-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot/2.0.6.RELEASE/spring-boot-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-autoconfigure/2.0.6.RELEASE/spring-boot-autoconfigure-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-logging/2.0.6.RELEASE/spring-boot-starter-logging-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/logging/log4j/log4j-to-slf4j/2.10.0/log4j-to-slf4j-2.10.0.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/logging/log4j/log4j-api/2.10.0/log4j-api-2.10.0.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/slf4j/jul-to-slf4j/1.7.25/jul-to-slf4j-1.7.25.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-json/2.0.6.RELEASE/spring-boot-starter-json-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/core/jackson-databind/2.9.7/jackson-databind-2.9.7.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/core/jackson-core/2.9.7/jackson-core-2.9.7.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.9.7/jackson-datatype-jdk8-2.9.7.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.9.7/jackson-datatype-jsr310-2.9.7.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/module/jackson-module-parameter-names/2.9.7/jackson-module-parameter-names-2.9.7.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-tomcat/2.0.6.RELEASE/spring-boot-starter-tomcat-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/tomcat/embed/tomcat-embed-core/8.5.34/tomcat-embed-core-8.5.34.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/tomcat/embed/tomcat-embed-el/8.5.34/tomcat-embed-el-8.5.34.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/tomcat/embed/tomcat-embed-websocket/8.5.34/tomcat-embed-websocket-8.5.34.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/hibernate/validator/hibernate-validator/6.0.13.Final/hibernate-validator-6.0.13.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/javax/validation/validation-api/2.0.1.Final/validation-api-2.0.1.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/jboss/logging/jboss-logging/3.3.2.Final/jboss-logging-3.3.2.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-web/5.0.10.RELEASE/spring-web-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-beans/5.0.10.RELEASE/spring-beans-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-webmvc/5.0.10.RELEASE/spring-webmvc-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-expression/5.0.10.RELEASE/spring-expression-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-core/5.0.10.RELEASE/spring-core-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-jcl/5.0.10.RELEASE/spring-jcl-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/projectlombok/lombok/1.16.22/lombok-1.16.22.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/alibaba/fastjson/1.2.60/fastjson-1.2.60.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/httpcomponents/httpclient/4.5.3/httpclient-4.5.3.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/httpcomponents/httpcore/4.4.10/httpcore-4.4.10.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/commons-codec/commons-codec/1.11/commons-codec-1.11.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/httpcomponents/httpmime/4.5.3/httpmime-4.5.3.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/httpcomponents/httpasyncclient/4.1/httpasyncclient-4.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/httpcomponents/httpcore-nio/4.4.10/httpcore-nio-4.4.10.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-aop/2.0.6.RELEASE/spring-boot-starter-aop-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-aop/5.0.10.RELEASE/spring-aop-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/aspectj/aspectjweaver/1.8.13/aspectjweaver-1.8.13.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/commons/commons-lang3/3.6/commons-lang3-3.6.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-data-redis/2.0.6.RELEASE/spring-boot-starter-data-redis-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/data/spring-data-redis/2.0.11.RELEASE/spring-data-redis-2.0.11.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/data/spring-data-keyvalue/2.0.11.RELEASE/spring-data-keyvalue-2.0.11.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/data/spring-data-commons/2.0.11.RELEASE/spring-data-commons-2.0.11.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-tx/5.0.10.RELEASE/spring-tx-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-oxm/5.0.10.RELEASE/spring-oxm-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/lettuce/lettuce-core/5.0.5.RELEASE/lettuce-core-5.0.5.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/projectreactor/reactor-core/3.1.10.RELEASE/reactor-core-3.1.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/reactivestreams/reactive-streams/1.0.2/reactive-streams-1.0.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-common/4.1.29.Final/netty-common-4.1.29.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-transport/4.1.29.Final/netty-transport-4.1.29.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-buffer/4.1.29.Final/netty-buffer-4.1.29.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-resolver/4.1.29.Final/netty-resolver-4.1.29.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-handler/4.1.29.Final/netty-handler-4.1.29.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-codec/4.1.29.Final/netty-codec-4.1.29.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/springfox/springfox-swagger2/2.9.2/springfox-swagger2-2.9.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/swagger/swagger-annotations/1.5.20/swagger-annotations-1.5.20.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/swagger/swagger-models/1.5.20/swagger-models-1.5.20.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/core/jackson-annotations/2.9.0/jackson-annotations-2.9.0.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/springfox/springfox-spi/2.9.2/springfox-spi-2.9.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/springfox/springfox-core/2.9.2/springfox-core-2.9.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/springfox/springfox-schema/2.9.2/springfox-schema-2.9.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/springfox/springfox-swagger-common/2.9.2/springfox-swagger-common-2.9.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/springfox/springfox-spring-web/2.9.2/springfox-spring-web-2.9.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/classmate/1.3.4/classmate-1.3.4.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/plugin/spring-plugin-core/1.2.0.RELEASE/spring-plugin-core-1.2.0.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/plugin/spring-plugin-metadata/1.2.0.RELEASE/spring-plugin-metadata-1.2.0.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/mapstruct/mapstruct/1.2.0.Final/mapstruct-1.2.0.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/springfox/springfox-swagger-ui/2.9.2/springfox-swagger-ui-2.9.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/junit/junit/4.12/junit-4.12.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/mockito/mockito-core/2.15.0/mockito-core-2.15.0.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/net/bytebuddy/byte-buddy/1.7.11/byte-buddy-1.7.11.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/net/bytebuddy/byte-buddy-agent/1.7.11/byte-buddy-agent-1.7.11.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/objenesis/objenesis/2.6/objenesis-2.6.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-configuration-processor/2.0.6.RELEASE/spring-boot-configuration-processor-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/commons-beanutils/commons-beanutils/1.9.3/commons-beanutils-1.9.3.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/commons-logging/commons-logging/1.2/commons-logging-1.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/commons-collections/commons-collections/3.2.2/commons-collections-3.2.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/commons/commons-pool2/2.6.1/commons-pool2-2.6.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/commons-net/commons-net/3.6/commons-net-3.6.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/guava/guava/23.0/guava-23.0.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/code/findbugs/jsr305/1.3.9/jsr305-1.3.9.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/errorprone/error_prone_annotations/2.0.18/error_prone_annotations-2.0.18.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/j2objc/j2objc-annotations/1.1/j2objc-annotations-1.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/codehaus/mojo/animal-sniffer-annotations/1.14/animal-sniffer-annotations-1.14.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/dom4j/dom4j/1.6.1/dom4j-1.6.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/xml-apis/xml-apis/1.4.01/xml-apis-1.4.01.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-mail/2.0.6.RELEASE/spring-boot-starter-mail-2.0.6.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-context/5.0.10.RELEASE/spring-context-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-context-support/5.0.10.RELEASE/spring-context-support-5.0.10.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/sun/mail/javax.mail/1.6.2/javax.mail-1.6.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/javax/activation/activation/1.1/activation-1.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/yaml/snakeyaml/1.25/snakeyaml-1.25.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/h2database/h2/1.4.199/h2-1.4.199.jar" enabled="true" runInBatchMode="false"/>
</factorypath>

View file

@ -0,0 +1,3 @@
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding/<project>=UTF-8

View file

@ -0,0 +1,4 @@
eclipse.preferences.version=1
org.eclipse.jdt.apt.aptEnabled=true
org.eclipse.jdt.apt.genSrcDir=target/generated-sources/annotations
org.eclipse.jdt.apt.genTestSrcDir=target/generated-test-sources/test-annotations

View file

@ -0,0 +1,10 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
org.eclipse.jdt.core.compiler.processAnnotations=enabled
org.eclipse.jdt.core.compiler.release=disabled
org.eclipse.jdt.core.compiler.source=1.8

View file

@ -0,0 +1,4 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

Some files were not shown because too many files have changed in this diff Show more