From 5479f3bb7b67c469f1a0e6e68e9bef8c38d9b350 Mon Sep 17 00:00:00 2001 From: Starnop Date: Thu, 18 Jul 2019 19:37:26 +0800 Subject: [PATCH] feature:implement supernode status switch Signed-off-by: yunfeiyangbuaa --- .circleci/config.yml | 3 +- CONTRIBUTORS | 2 +- apis/swagger.yml | 50 +++--- apis/types/df_get_task.go | 33 ++++ apis/types/task_create_request.go | 9 +- apis/types/task_info.go | 30 ---- apis/types/task_register_request.go | 24 +++ common/constants/dfget_super_code.go | 14 ++ dfdaemon/config/config.go | 2 +- dfdaemon/config/config_test.go | 2 +- docs/README.md | 2 +- docs/api_reference/apis.md | 2 + docs/quick_start/README.md | 15 +- docs/user_guide/docker_proxy.md | 2 +- docs/user_guide/install_client.md | 22 +-- docs/user_guide/install_server.md | 71 ++++---- docs/user_guide/install_server_go.md | 135 ---------------- docs/user_guide/multi_machines_deployment.md | 8 +- docs/user_guide/proxy.md | 2 +- docs/user_guide/supernode_configuration.md | 62 ------- go.mod | 1 + go.sum | 29 ++++ supernode/config/config.go | 13 ++ .../daemon/mgr/dfgettask/manager_test.go | 19 ++- supernode/daemon/mgr/ha/etcd_tool.go | 152 ++++++++++++++++++ supernode/daemon/mgr/ha/manager.go | 129 +++++++++++++++ supernode/daemon/mgr/ha/tool.go | 24 +++ supernode/daemon/mgr/ha_mgr.go | 19 +++ supernode/daemon/mgr/task/manager_util.go | 22 ++- .../daemon/mgr/task/manager_util_test.go | 4 - supernode/server/0.3_bridge.go | 20 +-- 31 files changed, 585 insertions(+), 337 deletions(-) delete mode 100644 docs/user_guide/install_server_go.md delete mode 100644 docs/user_guide/supernode_configuration.md mode change 100644 => 100755 go.mod mode change 100644 => 100755 go.sum create mode 100644 supernode/daemon/mgr/ha/etcd_tool.go create mode 100644 supernode/daemon/mgr/ha/manager.go create mode 100644 supernode/daemon/mgr/ha/tool.go create mode 100644 supernode/daemon/mgr/ha_mgr.go diff --git a/.circleci/config.yml b/.circleci/config.yml index a9a02b6ca..ac51c57a1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,9 +19,10 @@ jobs: name: use markdown-link-check(https://github.com/tcort/markdown-link-check) to check links in markdown files command: | set +e + curl -OfsSL https://raw.githubusercontent.com/dragonflyoss/dragonfly-scripts/master/config/markdown-link-check-scripts.json for name in $(find . -name \*.md | grep -v CHANGELOG); do if [ -f $name ]; then - markdown-link-check -q $name; + markdown-link-check -q -v -c ./markdown-link-check-scripts.json $name; if [ $? -ne 0 ]; then code=1 fi diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 43adbe498..ac9cd1d1e 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -1,7 +1,7 @@ # This file lists all contributors having contributed to this project. # For how it is generated, see command "git log --format='%aN <%aE>' | sort -uf". -Alan +alan Alibaba OSS aliwaredoc <42730518+aliwaredoc@users.noreply.github.com> Allen Sun diff --git a/apis/swagger.yml b/apis/swagger.yml index 70ecea0f9..f9c80af97 100644 --- a/apis/swagger.yml +++ b/apis/swagger.yml @@ -702,6 +702,13 @@ definitions: tells whether it is a call from dfdaemon. dfdaemon is a long running process which works for container engines. It translates the image pulling request into raw requests into those dfget recognizes. + callSystem: + type: "string" + description: | + This attribute represents where the dfget requests come from. Dfget will pass + this field to supernode and supernode can do some checking and filtering via + black/white list mechanism to guarantee security, or some other purposes like debugging. + minLength: 1 PeerCreateRequest: type: "object" @@ -840,9 +847,9 @@ definitions: callSystem: type: "string" description: | - This field is for debugging. When caller of dfget is using it to files, he can pass callSystem - name to dfget. When this field is passing to supernode, supernode has ability to filter them via - some black/white list to guarantee security, or some other purposes. + This attribute represents where the dfget requests come from. Dfget will pass + this field to supernode and supernode can do some checking and filtering via + black/white list mechanism to guarantee security, or some other purposes like debugging. minLength: 1 filter: type: "array" @@ -859,6 +866,10 @@ definitions: description: | PeerID is used to uniquely identifies a peer which will be used to create a dfgetTask. The value must be the value in the response after registering a peer. + supernodeIP: + type: "string" + description: "IP address of supernode which the peer connects to" + TaskCreateResponse: type: "object" @@ -954,20 +965,7 @@ definitions: from source server as user's wish. additionalProperties: type: "string" - dfdaemon: - type: "boolean" - description: | - tells whether it is a call from dfdaemon. dfdaemon is a long running - process which works for container engines. It translates the image - pulling request into raw requests into those dfget recganises. - callSystem: - type: "string" - description: | - This field is for debugging. When caller of dfget is using it to files, he can pass callSystem - name to dfget. When this field is passing to supernode, supernode has ability to filter them via - some black/white list to guarantee security, or some other purposes. - minLength: 1 - + TaskUpdateRequest: type: "object" description: "request used to update task attributes." @@ -1162,7 +1160,23 @@ definitions: PeerID uniquely identifies a peer, and the cID uniquely identifies a download task belonging to a peer. One peer can initiate multiple download tasks, which means that one peer corresponds to multiple cIDs. - + supernodeIP: + type: "string" + description: "IP address of supernode which the peer connects to" + dfdaemon: + type: "boolean" + description: | + tells whether it is a call from dfdaemon. dfdaemon is a long running + process which works for container engines. It translates the image + pulling request into raw requests into those dfget recganises. + callSystem: + type: "string" + description: | + This attribute represents where the dfget requests come from. Dfget will pass + this field to supernode and supernode can do some checking and filtering via + black/white list mechanism to guarantee security, or some other purposes like debugging. + minLength: 1 + ErrorResponse: type: "object" description: | diff --git a/apis/types/df_get_task.go b/apis/types/df_get_task.go index 2348c1234..ff0f300ef 100644 --- a/apis/types/df_get_task.go +++ b/apis/types/df_get_task.go @@ -27,6 +27,19 @@ type DfGetTask struct { // CID string `json:"cID,omitempty"` + // This attribute represents where the dfget requests come from. Dfget will pass + // this field to supernode and supernode can do some checking and filtering via + // black/white list mechanism to guarantee security, or some other purposes like debugging. + // + // Min Length: 1 + CallSystem string `json:"callSystem,omitempty"` + + // tells whether it is a call from dfdaemon. dfdaemon is a long running + // process which works for container engines. It translates the image + // pulling request into raw requests into those dfget recganises. + // + Dfdaemon bool `json:"dfdaemon,omitempty"` + // path is used in one peer A for uploading functionality. When peer B hopes // to get piece C from peer A, B must provide a URL for piece C. // Then when creating a task in supernode, peer A must provide this URL in request. @@ -50,6 +63,9 @@ type DfGetTask struct { // Enum: [WAITING RUNNING FAILED SUCCESS] Status string `json:"status,omitempty"` + // IP address of supernode which the peer connects to + SupernodeIP string `json:"supernodeIP,omitempty"` + // task Id TaskID string `json:"taskId,omitempty"` } @@ -58,6 +74,10 @@ type DfGetTask struct { func (m *DfGetTask) Validate(formats strfmt.Registry) error { var res []error + if err := m.validateCallSystem(formats); err != nil { + res = append(res, err) + } + if err := m.validateStatus(formats); err != nil { res = append(res, err) } @@ -68,6 +88,19 @@ func (m *DfGetTask) Validate(formats strfmt.Registry) error { return nil } +func (m *DfGetTask) validateCallSystem(formats strfmt.Registry) error { + + if swag.IsZero(m.CallSystem) { // not required + return nil + } + + if err := validate.MinLength("callSystem", "body", string(m.CallSystem), 1); err != nil { + return err + } + + return nil +} + var dfGetTaskTypeStatusPropEnum []interface{} func init() { diff --git a/apis/types/task_create_request.go b/apis/types/task_create_request.go index a829efe8f..c9eb85f21 100644 --- a/apis/types/task_create_request.go +++ b/apis/types/task_create_request.go @@ -24,9 +24,9 @@ type TaskCreateRequest struct { // CID string `json:"cID,omitempty"` - // This field is for debugging. When caller of dfget is using it to files, he can pass callSystem - // name to dfget. When this field is passing to supernode, supernode has ability to filter them via - // some black/white list to guarantee security, or some other purposes. + // This attribute represents where the dfget requests come from. Dfget will pass + // this field to supernode and supernode can do some checking and filtering via + // black/white list mechanism to guarantee security, or some other purposes like debugging. // // Min Length: 1 CallSystem string `json:"callSystem,omitempty"` @@ -83,6 +83,9 @@ type TaskCreateRequest struct { // RawURL string `json:"rawURL,omitempty"` + // IP address of supernode which the peer connects to + SupernodeIP string `json:"supernodeIP,omitempty"` + // taskURL is generated from rawURL. rawURL may contains some queries or parameter, dfget will filter some queries via // --filter parameter of dfget. The usage of it is that different rawURL may generate the same taskID. // diff --git a/apis/types/task_info.go b/apis/types/task_info.go index 719153c3e..f88a43985 100644 --- a/apis/types/task_info.go +++ b/apis/types/task_info.go @@ -22,24 +22,11 @@ type TaskInfo struct { // ID of the task. ID string `json:"ID,omitempty"` - // This field is for debugging. When caller of dfget is using it to files, he can pass callSystem - // name to dfget. When this field is passing to supernode, supernode has ability to filter them via - // some black/white list to guarantee security, or some other purposes. - // - // Min Length: 1 - CallSystem string `json:"callSystem,omitempty"` - // The status of the created task related to CDN functionality. // // Enum: [WAITING RUNNING FAILED SUCCESS SOURCE_ERROR] CdnStatus string `json:"cdnStatus,omitempty"` - // tells whether it is a call from dfdaemon. dfdaemon is a long running - // process which works for container engines. It translates the image - // pulling request into raw requests into those dfget recganises. - // - Dfdaemon bool `json:"dfdaemon,omitempty"` - // The length of the file dfget requests to download in bytes // which including the header and the trailer of each piece. // @@ -101,10 +88,6 @@ type TaskInfo struct { func (m *TaskInfo) Validate(formats strfmt.Registry) error { var res []error - if err := m.validateCallSystem(formats); err != nil { - res = append(res, err) - } - if err := m.validateCdnStatus(formats); err != nil { res = append(res, err) } @@ -115,19 +98,6 @@ func (m *TaskInfo) Validate(formats strfmt.Registry) error { return nil } -func (m *TaskInfo) validateCallSystem(formats strfmt.Registry) error { - - if swag.IsZero(m.CallSystem) { // not required - return nil - } - - if err := validate.MinLength("callSystem", "body", string(m.CallSystem), 1); err != nil { - return err - } - - return nil -} - var taskInfoTypeCdnStatusPropEnum []interface{} func init() { diff --git a/apis/types/task_register_request.go b/apis/types/task_register_request.go index 382973032..90886382f 100644 --- a/apis/types/task_register_request.go +++ b/apis/types/task_register_request.go @@ -28,6 +28,13 @@ type TaskRegisterRequest struct { // CID string `json:"cID,omitempty"` + // This attribute represents where the dfget requests come from. Dfget will pass + // this field to supernode and supernode can do some checking and filtering via + // black/white list mechanism to guarantee security, or some other purposes like debugging. + // + // Min Length: 1 + CallSystem string `json:"callSystem,omitempty"` + // tells whether it is a call from dfdaemon. dfdaemon is a long running // process which works for container engines. It translates the image // pulling request into raw requests into those dfget recognizes. @@ -100,6 +107,10 @@ func (m *TaskRegisterRequest) Validate(formats strfmt.Registry) error { res = append(res, err) } + if err := m.validateCallSystem(formats); err != nil { + res = append(res, err) + } + if err := m.validateHostName(formats); err != nil { res = append(res, err) } @@ -131,6 +142,19 @@ func (m *TaskRegisterRequest) validateIP(formats strfmt.Registry) error { return nil } +func (m *TaskRegisterRequest) validateCallSystem(formats strfmt.Registry) error { + + if swag.IsZero(m.CallSystem) { // not required + return nil + } + + if err := validate.MinLength("callSystem", "body", string(m.CallSystem), 1); err != nil { + return err + } + + return nil +} + func (m *TaskRegisterRequest) validateHostName(formats strfmt.Registry) error { if swag.IsZero(m.HostName) { // not required diff --git a/common/constants/dfget_super_code.go b/common/constants/dfget_super_code.go index b59c3fc75..a12c2ef2b 100644 --- a/common/constants/dfget_super_code.go +++ b/common/constants/dfget_super_code.go @@ -95,3 +95,17 @@ const ( ClientErrorFileNotExist = "FILE_NOT_EXIST" ClientErrorFileMd5NotMatch = "FILE_MD5_NOT_MATCH" ) + +/*the code of supernode ha status*/ +const ( + //SupernodeUseHaFalse means the supernode don't use ha + SupernodeUseHaFalse = 900 + //SupernodeUseHaInit means supernode use ha and the status is init + SupernodeUseHaInit = 901 + //SupernodeUseHaInit means supernode use ha and the status is standby + SupernodeUseHaStandby = 902 + //SupernodeUseHaInit means supernode use ha and the status is active + SupernodeUseHaActive = 903 + //SupernodeUseHaInit means supernode use ha and give up active status + SupernodeUsehakill = 904 +) diff --git a/dfdaemon/config/config.go b/dfdaemon/config/config.go index 56de62d3f..478bbc122 100644 --- a/dfdaemon/config/config.go +++ b/dfdaemon/config/config.go @@ -50,7 +50,7 @@ var fs = afero.NewOsFs() // // proxies: // # proxy all http image layer download requests with dfget -// - regx: blobs/sha256:.* +// - regx: blobs/sha256.* // # change http requests to some-registry to https and proxy them with dfget // - regx: some-registry/ // use_https: true diff --git a/dfdaemon/config/config_test.go b/dfdaemon/config/config_test.go index b384d90ff..e91d81964 100644 --- a/dfdaemon/config/config_test.go +++ b/dfdaemon/config/config_test.go @@ -252,7 +252,7 @@ func (ts *configTestSuite) TestProxyNew() { func (ts *configTestSuite) TestProxyMatch() { r := ts.Require() - p, err := NewProxy("blobs/sha256:.*", false, false) + p, err := NewProxy("blobs/sha256.*", false, false) r.Nil(err) r.NotNil(p) diff --git a/docs/README.md b/docs/README.md index 0eef3e411..d3ab71da1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -44,7 +44,7 @@ Develop Guide helps (potential) developers/contributors to understand the thoery ### Design Doc -[Design Doc](./design) is content all about deisgn of Dragonfly. It includes all things taken into consideration at the very beginning, the architecture designed for all components in Dragonfly, the interactive workflow between components, all APIs in Dragonfly and some technical things else. +[Design Doc](./design) is content all about design of Dragonfly. It includes all things taken into consideration at the very beginning, the architecture designed for all components in Dragonfly, the interactive workflow between components, all APIs in Dragonfly and some technical things else. ### Test Guide diff --git a/docs/api_reference/apis.md b/docs/api_reference/apis.md index f27b8263b..c9bef8d91 100644 --- a/docs/api_reference/apis.md +++ b/docs/api_reference/apis.md @@ -651,6 +651,7 @@ A download process initiated by dfget or other clients. |**peerID**
*optional*|PeerID uniquely identifies a peer, and the cID uniquely identifies a
download task belonging to a peer. One peer can initiate multiple download tasks,
which means that one peer corresponds to multiple cIDs.|string| |**pieceSize**
*optional*|The size of pieces which is calculated as per the following strategy
1. If file's total size is less than 200MB, then the piece size is 4MB by default.
2. Otherwise, it equals to the smaller value between totalSize/100MB + 2 MB and 15MB.|integer (int32)| |**status**
*optional*|The status of Dfget download process.|enum (WAITING, RUNNING, FAILED, SUCCESS)| +|**supernodeIP**
*optional*|IP address of supernode which the peer connects to|string| |**taskId**
*optional*||string| @@ -834,6 +835,7 @@ The returned information from supernode. |**path**
*optional*|path is used in one peer A for uploading functionality. When peer B hopes
to get piece C from peer A, B must provide a URL for piece C.
Then when creating a task in supernode, peer A must provide this URL in request.|string| |**peerID**
*optional*|PeerID is used to uniquely identifies a peer which will be used to create a dfgetTask.
The value must be the value in the response after registering a peer.|string| |**rawURL**
*optional*|The is the resource's URL which user uses dfget to download. The location of URL can be anywhere, LAN or WAN.
For image distribution, this is image layer's URL in image registry.
The resource url is provided by command line parameter.|string| +|**supernodeIP**
*optional*|IP address of supernode which the peer connects to|string| |**taskURL**
*optional*|taskURL is generated from rawURL. rawURL may contains some queries or parameter, dfget will filter some queries via
--filter parameter of dfget. The usage of it is that different rawURL may generate the same taskID.|string| diff --git a/docs/quick_start/README.md b/docs/quick_start/README.md index 06f3e827b..92233274a 100644 --- a/docs/quick_start/README.md +++ b/docs/quick_start/README.md @@ -11,7 +11,7 @@ All steps in this document are done on the same machine using the docker contain ## Step 1: Deploy Dragonfly Server (SuperNode) ```bash -docker run -d --name supernode --restart=always -p 8001:8001 -p 8002:8002 dragonflyoss/supernode:0.4.1 +docker run -d --name supernode --restart=always -p 8001:8001 -p 8002:8002 -v /home/admin/supernode:/home/admin/supernode dragonflyoss/supernode:0.4.2 ``` **NOTE**: @@ -22,12 +22,12 @@ docker run -d --name supernode --restart=always -p 8001:8001 -p 8002:8002 dragon ```bash SUPERNODE_IP=`docker inspect supernode -f '{{.NetworkSettings.Networks.bridge.IPAddress}}'` -docker run -d --name dfclient -p 65001:65001 dragonflyoss/dfclient:0.4.1 --registry https://index.docker.io --node $SUPERNODE_IP +docker run -d --name dfclient --restart=always -p 65001:65001 -v $HOME/.small-dragonfly:/root/.small-dragonfly dragonflyoss/dfclient:0.4.2 --registry https://index.docker.io --node $SUPERNODE_IP ``` **NOTE**: -- The `--registry` parameter specifies the mirrored image registry address, and `https://index.docker.io` is the address of official image registry, you can also set it to the others. +- The `--registry` parameter specifies the mirrored image registry address, and `https://index.docker.io` is the address of official image registry, you can also set it to the other **non-https image registries**. - The `--node` parameter specifies the supernode's ip address. Here we use `docker inspect` to get the ip of supernode container. Since the supernode container exposes its ports, you can specify this parameter to node ip address as well. ## Step 3. Configure Docker Daemon @@ -75,3 +75,12 @@ If the output of command above has content like ``` then Dragonfly is proved to work successfully. + +## SEE ALSO + +- [multi machines deployment](../user_guide/multi_machines_deployment.md) - experience Dragonfly on multiple machines +- [install server](../user_guide/install_server.md) - how to install the Dragonfly server +- [install client](../user_guide/install_client.md) - how to install the Dragonfly dfclient +- [docker proxy](../user_guide/docker_proxy.md) - make Dragonfly as HTTP proxy for docker daemon +- [proxy](../user_guide/proxy.md) - config proxy +- [download files](../user_guide/download_files.md) - download files with Dragonfly diff --git a/docs/user_guide/docker_proxy.md b/docs/user_guide/docker_proxy.md index 0424c7e22..90fe0c60d 100644 --- a/docs/user_guide/docker_proxy.md +++ b/docs/user_guide/docker_proxy.md @@ -8,7 +8,7 @@ To use dfdaemon as HTTP proxy, first you need to add a proxy rule in ```yaml proxies: -- regx: blobs/sha256:.* +- regx: blobs/sha256.* ``` This will proxy all requests for image layers with dfget. diff --git a/docs/user_guide/install_client.md b/docs/user_guide/install_client.md index c1626c55a..0a6e2fd28 100644 --- a/docs/user_guide/install_client.md +++ b/docs/user_guide/install_client.md @@ -16,23 +16,15 @@ You can install from the latest packages we provided. Available packages: - - If you're in China: + - [Linux 64-bit](https://github.com/dragonflyoss/Dragonfly/releases/download/v0.4.2/df-client_0.4.2_linux_amd64.tar.gz): `https://github.com/dragonflyoss/Dragonfly/releases/download/v0.4.2/df-client_0.4.2_linux_amd64.tar.gz` - - [Linux 64-bit](http://dragonflyoss.oss-cn-hangzhou.aliyuncs.com/df-client_0.4.0_linux_amd64.tar.gz): `http://dragonflyoss.oss-cn-hangzhou.aliyuncs.com/df-client_0.4.0_linux_amd64.tar.gz` - - - [MacOS 64-bit](http://dragonflyoss.oss-cn-hangzhou.aliyuncs.com/df-client_0.4.0_darwin_amd64.tar.gz): `http://dragonflyoss.oss-cn-hangzhou.aliyuncs.com/df-client_0.4.0_darwin_amd64.tar.gz` - - - If you're not in China: - - - [Linux 64-bit](https://github.com/dragonflyoss/Dragonfly/releases/download/v0.4.0/df-client_0.4.0_linux_amd64.tar.gz): `https://github.com/dragonflyoss/Dragonfly/releases/download/v0.4.0/df-client_0.4.0_linux_amd64.tar.gz` - - - [MacOS 64-bit](https://github.com/dragonflyoss/Dragonfly/releases/download/v0.4.0/df-client_0.4.0_darwin_amd64.tar.gz): `https://github.com/dragonflyoss/Dragonfly/releases/download/v0.4.0/df-client_0.4.0_darwin_amd64.tar.gz` + - [MacOS 64-bit](https://github.com/dragonflyoss/Dragonfly/releases/download/v0.4.2/df-client_0.4.2_darwin_amd64.tar.gz): `https://github.com/dragonflyoss/Dragonfly/releases/download/v0.4.2/df-client_0.4.2_darwin_amd64.tar.gz` 2. Unzip the package. ```bash # Replace `xxx` with the installation directory. - tar -zxf df-client_0.4.0_linux_amd64.tar.gz -C xxx + tar -zxf df-client_0.4.2_linux_amd64.tar.gz -C xxx ``` 3. Add the directory of `df-client` to your `PATH` environment variable to make sure you can directly use `dfget` and `dfdaemon` command. @@ -72,13 +64,13 @@ You can also install from the source code. 4. Install `dfdaemon` and `dfget` in `/opt/dragonfly/df-client` and create soft-link in `/usr/local/bin`. ```sh - sudo make install + sudo make install-client ``` ## After this Task Test if the downloading works. - ```sh - dfget --url "http://${resourceUrl}" --output ./resource.png --node "127.0.0.1:8002" - ``` +```sh +dfget --url "http://${resourceUrl}" --output ./resource.png --node "127.0.0.1:8002" +``` diff --git a/docs/user_guide/install_server.md b/docs/user_guide/install_server.md index e6732df71..c7debd55a 100644 --- a/docs/user_guide/install_server.md +++ b/docs/user_guide/install_server.md @@ -1,12 +1,12 @@ -# Installing Server +# Installing Dragonfly Server -This topic explains how to install the Dragonfly server. +This topic explains how to install the Dragonfly server with **Golang version**. -**Tip:** For a data center or a cluster, we recommend that you use at least two machines with eight cores, 16GB RAM and Gigabit Ethernet connections for deploying supernodes. +**NOTE**: The Golang version supernode is **not ready for production usage**. However, you can use it more easily in your test environment. ## Context -There are two layers in Dragonfly’s architecture: server (supernodes) and client (hosts). Install the supernodes in one of the following ways: +Install the SuperNodes in one of the following ways: - Deploying with Docker: Recommended for quick local deployment and test. - Deploying with physical machines: Recommended for production usage. @@ -25,12 +25,23 @@ When deploying with physical machines, the following conditions must be met. Required Software | Version Limit ---|--- Git|1.9.1+ -JDK|1.7+ -Maven|3.0.3+ +Golang|1.12.x Nginx|0.8+ ## Procedure - When Deploying with Docker +### Get SuperNode image + +You can get it from [DockerHub](https://hub.docker.com/) directly. + +1. Obtain the latest Docker image ID of the SuperNode. + + ```sh + docker pull dragonflyoss/supernode:0.4.2 + ``` + +Or you can build your own supernode image. + 1. Obtain the source code of Dragonfly. ```sh @@ -46,21 +57,27 @@ Nginx|0.8+ 3. Build the Docker image. ```sh - make build-supernode-java + TAG="0.4.2" + make docker-build-supernode DF_VERSION=$TAG ``` -4. Obtain the latest Docker image ID of the supernode. +4. Obtain the latest Docker image ID of the SuperNode. ```sh docker image ls|grep 'supernode' |awk '{print $3}' | head -n1 ``` -5. Start the supernode. +### Start the SuperNode - ```sh - # Replace ${supernodeDockerImageId} with the ID obtained at the previous step - docker run -d -p 8001:8001 -p 8002:8002 ${supernodeDockerImageId} - ``` +**NOTE**: Replace ${supernodeDockerImageId} with the ID obtained at the previous step. + +```sh +docker run -d --name supernode --restart=always -p 8001:8001 -p 8002:8002 -v /home/admin/supernode:/home/admin/supernode dragonflyoss/supernode:0.4.2 --download-port=8001 + +or + +docker run -d --name supernode --restart=always -p 8001:8001 -p 8002:8002 -v /home/admin/supernode:/home/admin/supernode ${supernodeDockerImageId} --download-port=8001 +``` ## Procedure - When Deploying with Physical Machines @@ -73,25 +90,24 @@ Nginx|0.8+ 2. Enter the project directory. ```sh - cd Dragonfly/src/supernode + cd Dragonfly ``` 3. Compile the source code. ```sh - mvn clean -U install -DskipTests=true + make build-supernode && make install ``` -4. Start the supernode. +4. Start the SuperNode. ```sh - # If the 'supernode.baseHome’ is not specified, then the default value '/home/admin/supernode’ will be used. - java -Dsupernode.baseHome=/home/admin/supernode -jar target/supernode.jar + supernode --home-dir=/home/admin/supernode --port=8002 --download-port=8001 --advertise-ip=127.0.0.1 ``` -5. Add the following configuration items to the Nginx configuration file. + **NOTE**: `advertise-ip` should be the ip that clients can connect to, `127.0.0.1` here is an example for testing, and it can only be used if the server and client are in the same machine. - **Tip:** The path of the Nginx configuration file is something like `src/supernode/src/main/docker/sources/nginx.conf`. +5. Add the following configuration items to the Nginx configuration file. ```conf server { @@ -101,13 +117,6 @@ Nginx|0.8+ root /home/admin/supernode/repo; } } - - server { - listen 8002; - location / { - proxy_pass http://127.0.0.1:8080; - } - } ``` 6. Start Nginx. @@ -118,17 +127,15 @@ Nginx|0.8+ ## After this Task -- After the supernode is installed, run the following commands to verify if Nginx and Tomcat are started, and if Port `8001` and `8002` are available. +- After the SuperNode is installed, run the following commands to verify if Nginx and **Supernode** are started, and if Port `8001` and `8002` are available. ```sh - ps aux|grep nginx - ps aux|grep tomcat telnet 127.0.0.1 8001 - telent 127.0.0.1 8002 + telnet 127.0.0.1 8002 ``` - Install the Dragonfly client and test if the downloading works. ```sh - dfget --url "http://${resourceUrl}" --output ./resource.png --node "127.0.0.1" + dfget --url "http://${resourceUrl}" --output ./resource.png --node "127.0.0.1:8002" ``` diff --git a/docs/user_guide/install_server_go.md b/docs/user_guide/install_server_go.md deleted file mode 100644 index 944dcee38..000000000 --- a/docs/user_guide/install_server_go.md +++ /dev/null @@ -1,135 +0,0 @@ -# Installing Dragonfly Server - -This topic explains how to install the Dragonfly server with **Golang version**. - -**NOTE**: The Golang version supernode is **not ready for production usage**. However, you can use it more easily in your test environment. - -## Context - -Install the SuperNodes in one of the following ways: - -- Deploying with Docker: Recommended for quick local deployment and test. -- Deploying with physical machines: Recommended for production usage. - -## Prerequisites - -When deploying with Docker, the following conditions must be met. - -Required Software | Version Limit ----|--- -Git|1.9.1+ -Docker|1.12.0+ - -When deploying with physical machines, the following conditions must be met. - -Required Software | Version Limit ----|--- -Git|1.9.1+ -Golang|1.12.x -Nginx|0.8+ - -## Procedure - When Deploying with Docker - -### Get Supernode image - -You can get it from [DockerHub](https://hub.docker.com/) directly. - -1. Obtain the latest Docker image ID of the SuperNode. - - ```sh - docker pull dragonflyoss/supernode:0.4.0 - ``` - -Or you can build your own supernode image. - -1. Obtain the source code of Dragonfly. - - ```sh - git clone https://github.com/dragonflyoss/Dragonfly.git - ``` - -2. Enter the project directory. - - ```sh - cd Dragonfly - ``` - -3. Build the Docker image. - - ```sh - TAG="test" - make docker-build-supernode DF_VERSION=$TAG - ``` - -4. Obtain the latest Docker image ID of the SuperNode. - - ```sh - docker image ls|grep 'supernode' |awk '{print $3}' | head -n1 - ``` - -### Start the SuperNode - -**NOTE**: Replace ${supernodeDockerImageId} with the ID obtained at the previous step. - -```sh -docker run -d --name dfsupernode -p 8002:8002 -v /home/admin/supernode:/home/admin/supernode ${supernodeDockerImageId} --advertise-ip=127.0.0.1 --download-port=8001 -``` - -## Procedure - When Deploying with Physical Machines - -1. Obtain the source code of Dragonfly. - - ```sh - git clone https://github.com/dragonflyoss/Dragonfly.git - ``` - -2. Enter the project directory. - - ```sh - cd Dragonfly - ``` - -3. Compile the source code. - - ```sh - make build-supernode && make install - ``` - -4. Start the SuperNode. - - ```sh - supernode --home-dir=/home/admin/supernode --port=8002 --advertise-ip=127.0.0.1 --download-port=8001 - ``` - -5. Add the following configuration items to the Nginx configuration file. - - ```conf - server { - listen 8001; - location / { - # Must be ${supernode.baseHome}/repo - root /home/admin/supernode/repo; - } - } - ``` - -6. Start Nginx. - - ```sh - sudo nginx - ``` - -## After this Task - -- After the SuperNode is installed, run the following commands to verify if Nginx and **Supernode** are started, and if Port `8001` and `8002` are available. - - ```sh - telnet 127.0.0.1 8001 - telnet 127.0.0.1 8002 - ``` - -- Install the Dragonfly client and test if the downloading works. - - ```sh - dfget --url "http://${resourceUrl}" --output ./resource.png --node "127.0.0.1:8002" - ``` diff --git a/docs/user_guide/multi_machines_deployment.md b/docs/user_guide/multi_machines_deployment.md index 93feaae28..9f027de8d 100644 --- a/docs/user_guide/multi_machines_deployment.md +++ b/docs/user_guide/multi_machines_deployment.md @@ -25,11 +25,10 @@ Then, we must provice: Deploy the Dragonfly server (Supernode) on the machine `dfsupernode`. ```bash -docker run -d --name supernode --restart=always -p 8001:8001 -p 8002:8002 \ - dragonflyoss/supernode:0.3.0 -Dsupernode.advertiseIp=dfsupernode +docker run -d --name supernode --restart=always -p 8001:8001 -p 8002:8002 -v /home/admin/supernode:/home/admin/supernode dragonflyoss/supernode:0.4.2 --download-port=8001 --advertise-ip=dfsupernode ``` -> **NOTE**: `supernode.advertiseIp` should be the ip that clients can connect to, `127.0.0.1` here is an example for testing, and it can only be used if the server and client are in the same machine. +> **NOTE**: `advertise-ip` should be the ip that clients can connect to. ## Step 2:Deploy Dragonfly Client (dfclient) @@ -53,7 +52,8 @@ EOD ```bash docker run -d --name dfclient --restart=always -p 65001:65001 \ -v /etc/dragonfly:/etc/dragonfly \ - dragonflyoss/dfclient:0.4.0 --registry https://index.docker.io + -v $HOME/.small-dragonfly:/root/.small-dragonfly \ + dragonflyoss/dfclient:0.4.2 --registry https://index.docker.io ``` **NOTE**: The `--registry` parameter specifies the mirrored image registry address, and `https://index.docker.io` is the address of official image registry, you can also set it to the others. diff --git a/docs/user_guide/proxy.md b/docs/user_guide/proxy.md index d1a9df3cd..04dc31ccc 100644 --- a/docs/user_guide/proxy.md +++ b/docs/user_guide/proxy.md @@ -14,7 +14,7 @@ Proxy rules are configured in `/etc/dragonfly/dfdaemon.yml`. # matching rule. proxies: # proxy all http image layer download requests with dfget -- regx: blobs/sha256:.* +- regx: blobs/sha256.* # proxy requests directly, without dfget - regx: no-proxy-reg direct: true diff --git a/docs/user_guide/supernode_configuration.md b/docs/user_guide/supernode_configuration.md deleted file mode 100644 index 6ab4249bd..000000000 --- a/docs/user_guide/supernode_configuration.md +++ /dev/null @@ -1,62 +0,0 @@ -# Supernode Configuration - -The supernode is written in Java based on Spring Boot. You can easily set properties with command line parameters or with the configuration file. - - -## Supernode Properties - -### Simple Property - -Property Name | Default Value | Description ----|---|--- -supernode.baseHome | /home/admin/supernode | Working directory of the supernode -supernode.systemNeedRate | 20 | Network rate reserved for the system (Unit: MB/s) -supernode.totalLimit | 200 | Network rate reserved for the supernode (Unit: MB/s) -supernode.schedulerCorePoolSize | 10 | Core pool size of ScheduledExecutorService -supernode.dfgetPath | /usr/local/bin/dfget/ | The `dfget` path - -### Cluster Property - -#### supernode.cluster - -This is an array property, and every member of it has these attributes: - -Name | Default Value | Description ----- | ------------- | ----------- -ip | None | The ip of the cluster member. -downloadPort | 8001 | The download port of the cluster member. -registerPort | 8002 | The register port of the cluster member. - -- Config it in `.properties` file, for example: - - ```ini - supernode.cluster[0].ip = '192.168.0.1' - supernode.cluster[0].registerPort = 8002 - supernode.cluster[1].ip = '192.168.0.2' - ``` - -- Config it in `.yaml` file, for example: - - ```yaml - supernode: - cluster: - - ip: '192.168.0.1' - registerPort: 8002 - - ip: '192.168.0.2' - ``` - -## Setting Properties - -You have two options when setting properties of a supernode. - -- Setting properties with command line parameters. - - ```bash - java -D= -jar supernode.jar - ``` - -- Setting properties with the configuration file. - - ```bash - java -Dspring.config.location=./config.properties, -jar supernode.jar - ``` diff --git a/go.mod b/go.mod old mode 100644 new mode 100755 index 7f5675924..5f33d16d3 --- a/go.mod +++ b/go.mod @@ -38,6 +38,7 @@ require ( github.com/stretchr/testify v1.2.2 github.com/valyala/fasthttp v1.3.0 github.com/willf/bitset v0.0.0-20190228212526-18bd95f470f9 + go.etcd.io/etcd v3.3.13+incompatible gopkg.in/gcfg.v1 v1.2.3 gopkg.in/mgo.v2 v2.0.0-20160818020120-3f83fa500528 // indirect gopkg.in/warnings.v0 v0.1.2 diff --git a/go.sum b/go.sum old mode 100644 new mode 100755 index 405f174ed..4ee4b1354 --- a/go.sum +++ b/go.sum @@ -16,19 +16,26 @@ github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/bbolt v1.3.2 h1:wZwiHHUieZCquLkDL0B8UhzreNWsPHooDAG3q34zk0s= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.7 h1:DVS0EPFHUiaJSaX2EKlaf65HUmk9PXhOl/Xa3Go242Q= github.com/cpuguy83/go-md2man v1.0.7/go.mod h1:N6JayAiVKtlHSnuTCeuLSQVs75hb8q+dYQLjr7cDsKY= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-check/check v0.0.0-20161208181325-20d25e280405 h1:0kdUKH22y+PT7ZITTEcrrHsQfGmpi4fj0XGyoDe/krQ= github.com/go-check/check v0.0.0-20161208181325-20d25e280405/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= @@ -57,8 +64,11 @@ github.com/go-openapi/validate v0.0.0-20170705144413-8a82927c942c h1:+cB2AzkH5an github.com/go-openapi/validate v0.0.0-20170705144413-8a82927c942c/go.mod h1:ve8xoSHgqBUifiKgaVbxLmOE0ckvH0oXfsJcnm6SIz0= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1 h1:G5FRp8JnTd7RQH5kemVNlMeyXQAztQ3mOWV95KxsXH8= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -67,20 +77,26 @@ github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/gorilla/context v0.0.0-20181012153548-51ce91d2eadd h1:bB2XEQHhNsTTpqNzsq5ObUuqR7RNIdpm5Phb6AjeejE= github.com/gorilla/context v0.0.0-20181012153548-51ce91d2eadd/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.5.0 h1:mq8bRov+5x+pZNR/uAHyUEgovR9gLgYFwDQIeuYi9TM= github.com/gorilla/mux v1.5.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0 h1:bM6ZAFZmc/wPFaRDi0d5L7hGEZEx/2u+Tmr2evNHDiI= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= @@ -136,6 +152,7 @@ github.com/russross/blackfriday v0.0.0-20171011182219-6d1ef893fcb0 h1:hgS5QyP981 github.com/russross/blackfriday v0.0.0-20171011182219-6d1ef893fcb0/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= @@ -155,7 +172,9 @@ github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/y github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= @@ -164,11 +183,18 @@ github.com/valyala/fasthttp v1.3.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/willf/bitset v0.0.0-20190228212526-18bd95f470f9 h1:WXBMTckrTcndPgRZBAEjqev+eN8MI9wbUQQUHlrUEV4= github.com/willf/bitset v0.0.0-20190228212526-18bd95f470f9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v3.3.13+incompatible h1:jCejD5EMnlGxFvcGRyEV4VGlENZc7oPQX6o0t7n3xbw= +go.etcd.io/etcd v3.3.13+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI= +go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= @@ -195,6 +221,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -202,8 +229,10 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190425150028-36563e24a262 h1:qsl9y/CJx34tuA7QCPNp86JNJe4spst6Ff8MjvPUdPg= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.21.0 h1:G+97AoqBnmZIT91cLG/EkCoK9NSelj64P8bOHHNmGn0= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/supernode/config/config.go b/supernode/config/config.go index 026be599c..f29a00c86 100644 --- a/supernode/config/config.go +++ b/supernode/config/config.go @@ -85,6 +85,8 @@ func NewBaseProperties() *BaseProperties { MaxBandwidth: 200, EnableProfiler: false, Debug: false, + UseHA: false, + HAConfig: []string{"127.0.0.1:2379"}, } } @@ -172,6 +174,17 @@ type BaseProperties struct { // superNodePID is the ID of supernode, which is the same as peer ID of dfget. superNodePID string + + //UseHA is the mark of whether the supernode use the ha model. + //ha means if the active supernode is off,the standby supernode can take over active supernode's work. + //and the whole system can work as before. + //default:false. + UseHA bool `yaml:"useHa"` + + //HAConfig is available when UseHa is true. + //HAConfig configs the tool's ip and port we use to implement ha. + //default:[] int {127.0.0.1:2379}. + HAConfig []string `yaml:"haConfig"` } // TransLimit trans rateLimit from MB/s to B/s. diff --git a/supernode/daemon/mgr/dfgettask/manager_test.go b/supernode/daemon/mgr/dfgettask/manager_test.go index 2de933e57..514d8fb05 100644 --- a/supernode/daemon/mgr/dfgettask/manager_test.go +++ b/supernode/daemon/mgr/dfgettask/manager_test.go @@ -35,10 +35,15 @@ func init() { } type DfgetTaskMgrTestSuite struct { + manager *Manager +} + +// SetUpSuite does common setup in the beginning of each test. +func (s *DfgetTaskMgrTestSuite) SetUpSuite(c *check.C) { + s.manager, _ = NewManager() } func (s *DfgetTaskMgrTestSuite) TestDfgetTaskMgr(c *check.C) { - dfgetTaskManager, _ := NewManager() clientID := "foo" taskID := "00c4e7b174af7ed61c414b36ef82810ac0c98142c03e5748c00e1d1113f3c882" @@ -51,11 +56,11 @@ func (s *DfgetTaskMgrTestSuite) TestDfgetTaskMgr(c *check.C) { PeerID: "foo-192.168.10.11-1553838710990554281", } - err := dfgetTaskManager.Add(context.Background(), dfgetTask) + err := s.manager.Add(context.Background(), dfgetTask) c.Check(err, check.IsNil) // Get - dt, err := dfgetTaskManager.Get(context.Background(), clientID, taskID) + dt, err := s.manager.Get(context.Background(), clientID, taskID) c.Check(err, check.IsNil) c.Check(dt, check.DeepEquals, &types.DfGetTask{ CID: clientID, @@ -67,10 +72,10 @@ func (s *DfgetTaskMgrTestSuite) TestDfgetTaskMgr(c *check.C) { }) // UpdateStatus - err = dfgetTaskManager.UpdateStatus(context.Background(), clientID, taskID, types.DfGetTaskStatusSUCCESS) + err = s.manager.UpdateStatus(context.Background(), clientID, taskID, types.DfGetTaskStatusSUCCESS) c.Check(err, check.IsNil) - dt, err = dfgetTaskManager.Get(context.Background(), clientID, taskID) + dt, err = s.manager.Get(context.Background(), clientID, taskID) c.Check(err, check.IsNil) c.Check(dt, check.DeepEquals, &types.DfGetTask{ CID: clientID, @@ -82,9 +87,9 @@ func (s *DfgetTaskMgrTestSuite) TestDfgetTaskMgr(c *check.C) { }) // Delete - err = dfgetTaskManager.Delete(context.Background(), clientID, taskID) + err = s.manager.Delete(context.Background(), clientID, taskID) c.Check(err, check.IsNil) - _, err = dfgetTaskManager.Get(context.Background(), clientID, taskID) + _, err = s.manager.Get(context.Background(), clientID, taskID) c.Check(errors.IsDataNotFound(err), check.Equals, true) } diff --git a/supernode/daemon/mgr/ha/etcd_tool.go b/supernode/daemon/mgr/ha/etcd_tool.go new file mode 100644 index 000000000..531088826 --- /dev/null +++ b/supernode/daemon/mgr/ha/etcd_tool.go @@ -0,0 +1,152 @@ +package ha + +import ( + "context" + "time" + + "github.com/dragonflyoss/Dragonfly/supernode/config" + + "github.com/sirupsen/logrus" + "go.etcd.io/etcd/clientv3" +) + +//EtcdMgr is the struct to manager etcd. +type EtcdMgr struct { + config clientv3.Config + client *clientv3.Client + leaseTTL int64 + leaseKeepAliveRsp <-chan *clientv3.LeaseKeepAliveResponse + hostIP string + leaseResp *clientv3.LeaseGrantResponse +} + +const ( + //ActiveSupernodeOFF means there is no active supernode. + ActiveSupernodeOFF = "" + //ActiveSupernodeChange means active supernode change to standby supernode because of unhealthy. + ActiveSupernodeChange = 0 + //ActiveSupernodeKeep means active supernode is health. + ActiveSupernodeKeep = 1 + //etcdTimeOut is the etcd client's timeout second + etcdTimeOut = 10 * time.Second + //activeKeyPreFIx is the keyPrefix of active supernode + activeKeyPreFIx = "/supernode/active/" + //standbyKeyPreFix is the keyPrefix of active supernode + //standbyKeyPreFix = "/supernode/standby/" +) + +//NewEtcdMgr produce a etcdmgr object. +func NewEtcdMgr(cfg *config.Config) (*EtcdMgr, error) { + config := clientv3.Config{ + Endpoints: cfg.HAConfig, + DialTimeout: etcdTimeOut, + } + // build connection to etcd. + client, err := clientv3.New(config) + return &EtcdMgr{ + hostIP: cfg.AdvertiseIP, + config: config, + client: client, + }, err +} + +//WatchActiveChange is the progress to watch the etcd,if the value of key /lock/active changes,supernode will be notified. +func (etcd *EtcdMgr) WatchActiveChange(ctx context.Context, messageChannel chan string) { + var watchStartRevision int64 + watcher := clientv3.NewWatcher(etcd.client) + watchChan := watcher.Watch(ctx, activeKeyPreFIx, clientv3.WithRev(watchStartRevision)) + for watchResp := range watchChan { + for _, event := range watchResp.Events { + switch event.Type { + case ActiveSupernodeChange: + messageChannel <- string(event.Kv.Value) + case ActiveSupernodeKeep: + messageChannel <- ActiveSupernodeOFF + default: + logrus.Warnf("failed to get watch active supernode,unexpected response: %d", int(event.Type)) + } + } + } +} + +//ObtainActiveInfo obtain the active supernode's information from etcd. +func (etcd *EtcdMgr) ObtainActiveInfo(ctx context.Context, key string) (string, error) { + var value string + kv := clientv3.NewKV(etcd.client) + getRes, err := kv.Get(ctx, key) + if err != nil { + logrus.Errorf("failed to get the active supernode's(key: %s) info: %v", key, err) + } + for _, v := range getRes.Kvs { + value = string(v.Value) + } + return value, err +} + +//ActiveResureItsStatus keep look on the lease's renew response. +func (etcd *EtcdMgr) ActiveResureItsStatus() { + for { + select { + case keepResp := <-etcd.leaseKeepAliveRsp: + if keepResp == nil { + logrus.Info("failed to renew the etcd lease") + return + } + } + } +} + +//TryBeActive try to change the supernode's status from standby to active. +func (etcd *EtcdMgr) TryBeActive(ctx context.Context) (bool, string, error) { + var ( + err error + leaseResp *clientv3.LeaseGrantResponse + keepRespChan <-chan *clientv3.LeaseKeepAliveResponse + txnResp *clientv3.TxnResponse + ) + kv := clientv3.NewKV(etcd.client) + //make a lease to obtain a lock + lease := clientv3.NewLease(etcd.client) + if leaseResp, err = lease.Grant(ctx, etcd.leaseTTL); err != nil { + logrus.Errorf("failed to create a etcd lease: %v", err) + } + if keepRespChan, err = lease.KeepAlive(ctx, leaseResp.ID); err != nil { + logrus.Errorf("failed to create etcd.leaseKeepAliveRsp: %v", err) + } + etcd.leaseKeepAliveRsp = keepRespChan + etcd.leaseResp = leaseResp + //if the lock is available,get the lock. + //else read the lock + txn := kv.Txn(ctx) + txn.If(clientv3.Compare(clientv3.CreateRevision(activeKeyPreFIx), "=", 0)). + Then(clientv3.OpPut(activeKeyPreFIx, etcd.hostIP, clientv3.WithLease(leaseResp.ID))). + Else(clientv3.OpGet(activeKeyPreFIx)) + if txnResp, err = txn.Commit(); err != nil { + logrus.Errorf("failed to commit a etcd transaction: %v", err) + } + if !txnResp.Succeeded { + _, err = lease.Revoke(ctx, leaseResp.ID) + return false, string(txnResp.Responses[0].GetResponseRange().Kvs[0].Value), err + } + return true, etcd.hostIP, nil +} + +//ActiveKillItself cancels the renew of lease. +func (etcd *EtcdMgr) ActiveKillItself(ctx context.Context) bool { + if _, err := etcd.client.Revoke(ctx, etcd.leaseResp.ID); err != nil { + logrus.Errorf("failed to cancel a etcd lease: %v", err) + return false + } + logrus.Info("success to cancel a etcd lease") + return true +} + +//Close close the tool used to implement supernode ha. +func (etcd *EtcdMgr) Close() error { + var err error + if err = etcd.client.Close(); err != nil { + return err + } + logrus.Info("success to close a etcd client") + return nil +} diff --git a/supernode/daemon/mgr/ha/manager.go b/supernode/daemon/mgr/ha/manager.go new file mode 100644 index 000000000..78ddcb48b --- /dev/null +++ b/supernode/daemon/mgr/ha/manager.go @@ -0,0 +1,129 @@ +package ha + +import ( + "context" + + "github.com/dragonflyoss/Dragonfly/common/constants" + "github.com/dragonflyoss/Dragonfly/supernode/config" + + "github.com/sirupsen/logrus" +) + +//Manager is the struct to manager supernode ha. +type Manager struct { + advertiseIP string + useHa bool + nodeStatus int + tool Tool +} + +//NewManager produce the Manager object. +func NewManager(cfg *config.Config) (*Manager, error) { + //TODO(yunfeiyangbuaa): handle the NewEtcdMgr(cfg) in the future + toolMgr, err := NewEtcdMgr(cfg) + if err != nil { + logrus.Errorf("failed to init the ha tool: %v", err) + return nil, err + } + return &Manager{ + advertiseIP: cfg.AdvertiseIP, + useHa: cfg.UseHA, + nodeStatus: constants.SupernodeUseHaInit, + tool: toolMgr, + }, nil +} + +//ElectDaemon is the main progress to implement active/standby switch. +func (ha *Manager) ElectDaemon(change chan int) { + messageChannel := make(chan string) + //a process to watch whether the active supernode is off. + go ha.watchActive(messageChannel) + //a process try to get the active supernode when the supernode is start. + go ha.tryStandbyToActive(change) + for { + if activeIP, ok := <-messageChannel; ok { + //when the active node is off. + if activeIP == ActiveSupernodeOFF { + //if the previous active supernode is itself,change its status to standby to avoid brain split. + if ha.nodeStatus == constants.SupernodeUseHaActive { + ha.activeToStandby() + change <- constants.SupernodeUsehakill + } else { + ha.tryStandbyToActive(change) + } + } + } + } + +} + +//GetSupernodeStatus get supernode's status. +func (ha *Manager) GetSupernodeStatus() int { + if ha.useHa == false { + return constants.SupernodeUseHaFalse + } + return ha.nodeStatus +} + +//CompareAndSetSupernodeStatus set supernode's status. +func (ha *Manager) CompareAndSetSupernodeStatus(preStatus int, nowStatus int) bool { + if ha.nodeStatus == preStatus { + ha.nodeStatus = nowStatus + return true + } + logrus.Errorf("failed to set supernode status,the preStatus is %d not equal to %d", ha.nodeStatus, preStatus) + return false +} + +//CloseHaManager close the tool use to implement supernode ha. +func (ha *Manager) CloseHaManager() error { + return ha.tool.Close() +} + +//GiveUpActiveStatus give up its active status because of unhealthy. +func (ha *Manager) GiveUpActiveStatus() bool { + return ha.tool.ActiveKillItself(context.TODO()) +} + +//StandbyToActive change the status from standby to active. +func (ha *Manager) standbyToActive() { + if ha.nodeStatus == constants.SupernodeUseHaStandby { + ha.nodeStatus = constants.SupernodeUseHaActive + return + } + logrus.Warnf("failed to become active,because %s is already active,can't set it active again", ha.advertiseIP) + +} + +//ActiveToStandby change the status from active to standby. +func (ha *Manager) activeToStandby() { + if ha.nodeStatus == constants.SupernodeUseHaActive { + ha.nodeStatus = constants.SupernodeUseHaStandby + return + } + logrus.Warnf("failed to become standby,%s is already standby,can't set it standby again", ha.advertiseIP) +} + +//TryStandbyToActive try to change the status from standby to active. +func (ha *Manager) tryStandbyToActive(change chan int) { + success, ip, err := ha.tool.TryBeActive(context.TODO()) + if err != nil { + logrus.Errorf("failed to try to change standby status to active status") + } + if success == true { + ha.standbyToActive() + logrus.Infof("%s obtain the active supernode status", ha.advertiseIP) + change <- constants.SupernodeUseHaActive + ha.tool.ActiveResureItsStatus() + ha.activeToStandby() + logrus.Infof("%s finishes the active supernode status", ha.advertiseIP) + } else { + logrus.Infof("the other supernode %s obtain the active supernode status,keep watch on it", ip) + change <- constants.SupernodeUseHaStandby + } +} + +//WatchActive keep watch whether the active supernode is off. +func (ha *Manager) watchActive(messageChannel chan string) { + ha.tool.WatchActiveChange(context.TODO(), messageChannel) +} diff --git a/supernode/daemon/mgr/ha/tool.go b/supernode/daemon/mgr/ha/tool.go new file mode 100644 index 000000000..d6774d2f5 --- /dev/null +++ b/supernode/daemon/mgr/ha/tool.go @@ -0,0 +1,24 @@ +package ha + +import "context" + +//Tool is an interface that use etcd/zookeeper/yourImplement tools to make supernode be standby or active. +type Tool interface { + //WatchActiveChange keeps watching the status of active supernode. + WatchActiveChange(ctx context.Context, messageChannel chan string) + + //ObtainActiveInfo obtains the active supernode's info(Ip address and port). + ObtainActiveInfo(ctx context.Context, key string) (string, error) + + //TryBeActive try to make standby supernode to be active. + TryBeActive(ctx context.Context) (bool, string, error) + + //ActiveResureItsStatus will keep to monitor to ensure this itself is still a active supernode now. + ActiveResureItsStatus() + + //ActiveKillItself abandon the active status and the active supernode become standby supernode. + ActiveKillItself(ctx context.Context) bool + + //Close close the tool. + Close() error +} diff --git a/supernode/daemon/mgr/ha_mgr.go b/supernode/daemon/mgr/ha_mgr.go new file mode 100644 index 000000000..437613220 --- /dev/null +++ b/supernode/daemon/mgr/ha_mgr.go @@ -0,0 +1,19 @@ +package mgr + +//HaMgr is the interface to implement supernode Ha. +type HaMgr interface { + //ElectDaemonthe is the daemon progress to implement active/standby switch. + ElectDaemon(change chan int) + + //HagetSupernodeState get supernode's status. + GetSupernodeStatus() int + + //HaSetSupernodeState compare and set supernode's status. + CompareAndSetSupernodeStatus(preStatus int, nowStatus int) bool + + //CloseHaManager close the tool used to implement supernode ha. + CloseHaManager() error + + //GiveUpActiveStatus give up its active status because of unhealthy. + GiveUpActiveStatus() bool +} diff --git a/supernode/daemon/mgr/task/manager_util.go b/supernode/daemon/mgr/task/manager_util.go index 3c327350a..547ab348b 100644 --- a/supernode/daemon/mgr/task/manager_util.go +++ b/supernode/daemon/mgr/task/manager_util.go @@ -28,8 +28,6 @@ func (tm *Manager) addOrUpdateTask(ctx context.Context, req *types.TaskCreateReq var task *types.TaskInfo newTask := &types.TaskInfo{ ID: taskID, - CallSystem: req.CallSystem, - Dfdaemon: req.Dfdaemon, Headers: req.Headers, Identifier: req.Identifier, Md5: req.Md5, @@ -154,12 +152,15 @@ func (tm *Manager) updateTask(taskID string, updateTaskInfo *types.TaskInfo) err func (tm *Manager) addDfgetTask(ctx context.Context, req *types.TaskCreateRequest, task *types.TaskInfo) (*types.DfGetTask, error) { dfgetTask := &types.DfGetTask{ - CID: req.CID, - Path: req.Path, - PieceSize: task.PieceSize, - Status: types.DfGetTaskStatusWAITING, - TaskID: task.ID, - PeerID: req.PeerID, + CID: req.CID, + CallSystem: req.CallSystem, + Dfdaemon: req.Dfdaemon, + Path: req.Path, + PieceSize: task.PieceSize, + Status: types.DfGetTaskStatusWAITING, + TaskID: task.ID, + PeerID: req.PeerID, + SupernodeIP: req.SupernodeIP, } if err := tm.dfgetTaskMgr.Add(ctx, dfgetTask); err != nil { @@ -301,6 +302,11 @@ func (tm *Manager) parseAvailablePeers(ctx context.Context, clientID string, tas return false, nil, err } + // get supernode IP according to the cid dynamically + if tm.cfg.IsSuperPID(pieceInfo.PID) { + pieceInfo.PeerIP = dfgetTask.SupernodeIP + } + pieceInfos = append(pieceInfos, pieceInfo) } diff --git a/supernode/daemon/mgr/task/manager_util_test.go b/supernode/daemon/mgr/task/manager_util_test.go index e6ee9c271..5df0ffc9f 100644 --- a/supernode/daemon/mgr/task/manager_util_test.go +++ b/supernode/daemon/mgr/task/manager_util_test.go @@ -81,9 +81,7 @@ func (s *TaskUtilTestSuite) TestAddOrUpdateTask(c *check.C) { }, task: &types.TaskInfo{ ID: generateTaskID("http://aa.bb.com", "", ""), - CallSystem: "foo", CdnStatus: types.TaskInfoCdnStatusWAITING, - Dfdaemon: true, HTTPFileLength: 1000, PieceSize: config.DefaultPieceSize, PieceTotal: 1, @@ -103,9 +101,7 @@ func (s *TaskUtilTestSuite) TestAddOrUpdateTask(c *check.C) { }, task: &types.TaskInfo{ ID: generateTaskID("http://aa.bb.com", "", ""), - CallSystem: "foo", CdnStatus: types.TaskInfoCdnStatusWAITING, - Dfdaemon: true, HTTPFileLength: 1000, PieceSize: config.DefaultPieceSize, PieceTotal: 1, diff --git a/supernode/server/0.3_bridge.go b/supernode/server/0.3_bridge.go index ab524a6ae..919f6c009 100644 --- a/supernode/server/0.3_bridge.go +++ b/supernode/server/0.3_bridge.go @@ -76,15 +76,17 @@ func (s *Server) registry(ctx context.Context, rw http.ResponseWriter, req *http peerID := peerCreateResponse.ID taskCreateRequest := &types.TaskCreateRequest{ - CID: request.CID, - Dfdaemon: request.Dfdaemon, - Headers: cutil.ConvertHeaders(request.Headers), - Identifier: request.Identifier, - Md5: request.Md5, - Path: request.Path, - PeerID: peerID, - RawURL: request.RawURL, - TaskURL: request.TaskURL, + CID: request.CID, + CallSystem: request.CallSystem, + Dfdaemon: request.Dfdaemon, + Headers: cutil.ConvertHeaders(request.Headers), + Identifier: request.Identifier, + Md5: request.Md5, + Path: request.Path, + PeerID: peerID, + RawURL: request.RawURL, + TaskURL: request.TaskURL, + SupernodeIP: request.SuperNodeIP.String(), } resp, err := s.TaskMgr.Register(ctx, taskCreateRequest) if err != nil {