This is an automated email from the ASF dual-hosted git repository.

morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 19fdadab4c3 [enchement](api)Change the behavior of follower http api 
redirect to master to follower request master. (#45921)
19fdadab4c3 is described below

commit 19fdadab4c37e7848e49c01a7c38d19ce1f246a9
Author: daidai <[email protected]>
AuthorDate: Thu Jan 2 12:30:55 2025 +0800

    [enchement](api)Change the behavior of follower http api redirect to master 
to follower request master. (#45921)
    
    ### What problem does this PR solve?
    
    Problem Summary:
    Change the behavior of follower http api redirecting to master to
    follower requesting master.
    Before this, when client sends http api request to follower, some api
    interfaces will send redirect request to client, and client will send
    request to master. However, in k8s scenario, there may be network
    disconnection between client and master, so this pr changes this
    behavior.
    
    ### Release note
    
    Change the behavior of follower http api redirecting to master to
    follower requesting master.
---
 .../doris/httpv2/meta/ColocateMetaService.java     |  18 +-
 .../apache/doris/httpv2/rest/CancelLoadAction.java |   5 +-
 .../doris/httpv2/rest/GetLoadInfoAction.java       |   9 +-
 .../doris/httpv2/rest/GetStreamLoadState.java      |   9 +-
 .../org/apache/doris/httpv2/rest/LoadAction.java   |   5 +-
 .../org/apache/doris/httpv2/rest/MultiAction.java  |  33 ++-
 .../doris/httpv2/rest/RestBaseController.java      | 106 +++++++++-
 .../org/apache/doris/httpv2/rest/ShowAction.java   |  15 +-
 .../doris/httpv2/rest/manager/NodeAction.java      |  24 ++-
 .../httpv2/restv2/AddStoragePolicyAction.java      |   8 +-
 .../doris/httpv2/restv2/ESCatalogAction.java       |  12 +-
 .../doris/httpv2/restv2/StatisticAction.java       |  11 +-
 .../org/apache/doris/http/ForwardToMasterTest.java | 233 +++++++++++++++++++++
 13 files changed, 412 insertions(+), 76 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/meta/ColocateMetaService.java
 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/meta/ColocateMetaService.java
index b7c2a615aac..8adb2147054 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/meta/ColocateMetaService.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/meta/ColocateMetaService.java
@@ -36,7 +36,6 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.servlet.view.RedirectView;
 
 import java.lang.reflect.Type;
 import java.util.List;
@@ -78,7 +77,7 @@ public class ColocateMetaService extends RestBaseController {
         GroupId groupId = new GroupId(dbId, grpId);
 
         if (!colocateIndex.isGroupExist(groupId)) {
-            throw new DdlException("the group " + groupId + "isn't  exist");
+            throw new DdlException("the group " + groupId + " isn't exist");
         }
         return groupId;
     }
@@ -86,16 +85,19 @@ public class ColocateMetaService extends RestBaseController 
{
     public Object executeWithoutPassword(HttpServletRequest request, 
HttpServletResponse response)
             throws Exception {
         executeCheckPassword(request, response);
-        RedirectView redirectView = redirectToMasterOrException(request, 
response);
-        if (redirectView != null) {
-            return redirectView;
-        }
         checkGlobalAuth(ConnectContext.get().getCurrentUserIdentity(), 
PrivPredicate.ADMIN);
         return null;
     }
 
     @RequestMapping(path = "/api/colocate", method = RequestMethod.GET)
     public Object colocate(HttpServletRequest request, HttpServletResponse 
response) throws Exception {
+        if (needRedirect(request.getScheme())) {
+            return redirectToHttps(request);
+        }
+
+        if (checkForwardToMaster(request)) {
+            return forwardToMaster(request);
+        }
         executeWithoutPassword(request, response);
         return ResponseEntityBuilder.ok(Env.getCurrentColocateIndex());
     }
@@ -107,6 +109,10 @@ public class ColocateMetaService extends 
RestBaseController {
             return redirectToHttps(request);
         }
 
+        if (checkForwardToMaster(request)) {
+            return forwardToMaster(request);
+        }
+
         executeWithoutPassword(request, response);
         GroupId groupId = checkAndGetGroupId(request);
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/CancelLoadAction.java 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/CancelLoadAction.java
index 3d0e7bc7c91..59c0579747a 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/CancelLoadAction.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/CancelLoadAction.java
@@ -50,9 +50,8 @@ public class CancelLoadAction extends RestBaseController {
         }
 
         executeCheckPassword(request, response);
-        Object redirectView = redirectToMaster(request, response);
-        if (redirectView != null) {
-            return redirectView;
+        if (checkForwardToMaster(request)) {
+            return forwardToMaster(request);
         }
 
         if (Strings.isNullOrEmpty(dbName)) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/GetLoadInfoAction.java 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/GetLoadInfoAction.java
index 4f80f74ca51..6a16459adb0 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/GetLoadInfoAction.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/GetLoadInfoAction.java
@@ -55,6 +55,9 @@ public class GetLoadInfoAction extends RestBaseController {
     public Object execute(
             @PathVariable(value = DB_KEY) final String dbName,
             HttpServletRequest request, HttpServletResponse response) {
+        if (needRedirect(request.getScheme())) {
+            return redirectToHttps(request);
+        }
         executeCheckPassword(request, response);
 
         String fullDbName = getFullDbName(dbName);
@@ -67,10 +70,8 @@ public class GetLoadInfoAction extends RestBaseController {
         if (Strings.isNullOrEmpty(info.label)) {
             return new RestBaseResult("No label selected");
         }
-
-        Object redirectView = redirectToMaster(request, response);
-        if (redirectView != null) {
-            return redirectView;
+        if (checkForwardToMaster(request)) {
+            return forwardToMaster(request);
         }
 
         try {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/GetStreamLoadState.java 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/GetStreamLoadState.java
index 95ac8266043..cf7bbee2b0f 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/GetStreamLoadState.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/GetStreamLoadState.java
@@ -38,9 +38,12 @@ public class GetStreamLoadState extends RestBaseController {
                           HttpServletRequest request, HttpServletResponse 
response) {
         executeCheckPassword(request, response);
 
-        Object redirectView = redirectToMaster(request, response);
-        if (redirectView != null) {
-            return redirectView;
+        if (needRedirect(request.getScheme())) {
+            return redirectToHttps(request);
+        }
+
+        if (checkForwardToMaster(request)) {
+            return forwardToMaster(request);
         }
 
         String label = request.getParameter(LABEL_KEY);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/LoadAction.java 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/LoadAction.java
index ddf0177bfe6..12ec330bbfa 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/LoadAction.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/LoadAction.java
@@ -321,9 +321,8 @@ public class LoadAction extends RestBaseController {
             if (!isStreamLoad && 
!Strings.isNullOrEmpty(request.getParameter(SUB_LABEL_NAME_PARAM))) {
                 // only multi mini load need to redirect to Master, because 
only Master has the info of table to
                 // the Backend which the file exists.
-                Object redirectView = redirectToMaster(request, response);
-                if (redirectView != null) {
-                    return redirectView;
+                if (checkForwardToMaster(request)) {
+                    return forwardToMaster(request);
                 }
                 try {
                     redirectAddr = 
execEnv.getMultiLoadMgr().redirectAddr(fullDbName, label);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/MultiAction.java 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/MultiAction.java
index 66522f7ece5..368dadebc02 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/MultiAction.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/MultiAction.java
@@ -66,9 +66,8 @@ public class MultiAction extends RestBaseController {
             checkDbAuth(ConnectContext.get().getCurrentUserIdentity(), 
fullDbName, PrivPredicate.LOAD);
 
             // only Master has these load info
-            Object redirectView = redirectToMaster(request, response);
-            if (redirectView != null) {
-                return redirectView;
+            if (checkForwardToMaster(request)) {
+                return forwardToMaster(request);
             }
 
             final List<String> labels = Lists.newArrayList();
@@ -95,9 +94,8 @@ public class MultiAction extends RestBaseController {
             checkDbAuth(ConnectContext.get().getCurrentUserIdentity(), 
fullDbName, PrivPredicate.LOAD);
 
             // only Master has these load info
-            Object redirectView = redirectToMaster(request, response);
-            if (redirectView != null) {
-                return redirectView;
+            if (checkForwardToMaster(request)) {
+                return forwardToMaster(request);
             }
 
             final List<String> labels = Lists.newArrayList();
@@ -129,10 +127,8 @@ public class MultiAction extends RestBaseController {
 
             // Multi start request must redirect to master, because all 
following sub requests will be handled
             // on Master
-
-            Object redirectView = redirectToMaster(request, response);
-            if (redirectView != null) {
-                return redirectView;
+            if (checkForwardToMaster(request)) {
+                return forwardToMaster(request);
             }
 
             Map<String, String> properties = Maps.newHashMap();
@@ -180,9 +176,8 @@ public class MultiAction extends RestBaseController {
             String fullDbName = getFullDbName(dbName);
             checkDbAuth(ConnectContext.get().getCurrentUserIdentity(), 
fullDbName, PrivPredicate.LOAD);
 
-            Object redirectView = redirectToMaster(request, response);
-            if (redirectView != null) {
-                return redirectView;
+            if (checkForwardToMaster(request)) {
+                return forwardToMaster(request);
             }
 
             ExecuteEnv.getInstance().getMultiLoadMgr().unload(fullDbName, 
label, subLabel);
@@ -213,11 +208,10 @@ public class MultiAction extends RestBaseController {
             checkDbAuth(ConnectContext.get().getCurrentUserIdentity(), 
fullDbName, PrivPredicate.LOAD);
 
             // only Master has these load info
-
-            Object redirectView = redirectToMaster(request, response);
-            if (redirectView != null) {
-                return redirectView;
+            if (checkForwardToMaster(request)) {
+                return forwardToMaster(request);
             }
+
             try {
                 ExecuteEnv.getInstance().getMultiLoadMgr().commit(fullDbName, 
label);
             } catch (Exception e) {
@@ -250,9 +244,8 @@ public class MultiAction extends RestBaseController {
             checkDbAuth(ConnectContext.get().getCurrentUserIdentity(), 
fullDbName, PrivPredicate.LOAD);
 
             // only Master has these load info
-            Object redirectView = redirectToMaster(request, response);
-            if (redirectView != null) {
-                return redirectView;
+            if (checkForwardToMaster(request)) {
+                return forwardToMaster(request);
             }
 
             ExecuteEnv.getInstance().getMultiLoadMgr().abort(fullDbName, 
label);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/RestBaseController.java 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/RestBaseController.java
index 48057463cd9..7f4f519cd17 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/RestBaseController.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/RestBaseController.java
@@ -21,6 +21,7 @@ import org.apache.doris.analysis.UserIdentity;
 import org.apache.doris.catalog.Env;
 import org.apache.doris.cluster.ClusterNamespace;
 import org.apache.doris.common.Config;
+import org.apache.doris.common.FeConstants;
 import org.apache.doris.common.util.NetUtils;
 import org.apache.doris.httpv2.controller.BaseController;
 import org.apache.doris.httpv2.entity.ResponseEntityBuilder;
@@ -31,19 +32,28 @@ import org.apache.doris.thrift.TNetworkAddress;
 
 import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
+import jline.internal.Nullable;
 import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
 import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.client.RestTemplate;
 import org.springframework.web.servlet.view.RedirectView;
 
 import java.io.BufferedInputStream;
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.util.Collections;
+import java.util.stream.Collectors;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -57,6 +67,7 @@ public class RestBaseController extends BaseController {
     protected static final String TXN_ID_KEY = "txn_id";
     protected static final String TXN_OPERATION_KEY = "txn_operation";
     protected static final String SINGLE_REPLICA_KEY = "single_replica";
+    protected static final String FORWARD_MASTER_UT_TEST = 
"forward_master_ut_test";
     private static final Logger LOG = 
LogManager.getLogger(RestBaseController.class);
 
     public ActionAuthorizationInfo executeCheckPassword(HttpServletRequest 
request,
@@ -74,6 +85,13 @@ public class RestBaseController extends BaseController {
     }
 
     public RedirectView redirectTo(HttpServletRequest request, TNetworkAddress 
addr) {
+        RedirectView redirectView = new RedirectView(getRedirectUrL(request, 
addr));
+        redirectView.setContentType("text/html;charset=utf-8");
+        
redirectView.setStatusCode(org.springframework.http.HttpStatus.TEMPORARY_REDIRECT);
+        return redirectView;
+    }
+
+    public String getRedirectUrL(HttpServletRequest request, TNetworkAddress 
addr) {
         URI urlObj = null;
         URI resultUriObj = null;
         String urlStr = request.getRequestURI();
@@ -85,7 +103,7 @@ public class RestBaseController extends BaseController {
         }
         try {
             urlObj = new URI(urlStr);
-            resultUriObj = new URI("http", userInfo, addr.getHostname(),
+            resultUriObj = new URI(request.getScheme(), userInfo, 
addr.getHostname(),
                     addr.getPort(), urlObj.getPath(), "", null);
         } catch (Exception e) {
             throw new RuntimeException(e);
@@ -94,12 +112,9 @@ public class RestBaseController extends BaseController {
         if (!Strings.isNullOrEmpty(request.getQueryString())) {
             redirectUrl += request.getQueryString();
         }
-        LOG.info("Redirect url: {}", "http://"; + addr.getHostname() + ":"
-                    + addr.getPort() + urlObj.getPath());
-        RedirectView redirectView = new RedirectView(redirectUrl);
-        redirectView.setContentType("text/html;charset=utf-8");
-        
redirectView.setStatusCode(org.springframework.http.HttpStatus.TEMPORARY_REDIRECT);
-        return redirectView;
+        LOG.info("Redirect url: {}", request.getScheme() + "://" + 
addr.getHostname() + ":"
+                + addr.getPort() + urlObj.getPath());
+        return redirectUrl;
     }
 
     public RedirectView redirectToObj(String sign) throws URISyntaxException {
@@ -198,4 +213,81 @@ public class RestBaseController extends BaseController {
         redirectView.setStatusCode(HttpStatus.TEMPORARY_REDIRECT);
         return redirectView;
     }
+
+    public Object forwardToMaster(HttpServletRequest request) {
+        try {
+            return forwardToMaster(request, (Object) getRequestBody(request));
+        } catch (Exception e) {
+            LOG.warn(e);
+            return ResponseEntityBuilder.okWithCommonError(e.getMessage());
+        }
+    }
+
+    public boolean checkForwardToMaster(HttpServletRequest request) {
+        if (FeConstants.runningUnitTest) {
+            String forbidForward = request.getHeader(FORWARD_MASTER_UT_TEST);
+            if (forbidForward != null) {
+                return "true".equals(forbidForward);
+            }
+        }
+        return !Env.getCurrentEnv().isMaster();
+    }
+
+
+    private String getRequestBody(HttpServletRequest request) throws 
IOException {
+        BufferedReader reader = request.getReader();
+        return 
reader.lines().collect(Collectors.joining(System.lineSeparator()));
+    }
+
+    public Object forwardToMaster(HttpServletRequest request, @Nullable Object 
body) {
+        try {
+            Env env = Env.getCurrentEnv();
+            String redirectUrl = null;
+            if (FeConstants.runningUnitTest) {
+                redirectUrl =
+                        getRedirectUrL(request, new 
TNetworkAddress(request.getServerName(), request.getServerPort()));
+            } else {
+                redirectUrl = getRedirectUrL(request,
+                        new TNetworkAddress(env.getMasterHost(), 
env.getMasterHttpPort()));
+            }
+            String method = request.getMethod();
+
+            HttpHeaders headers = new HttpHeaders();
+            for (String headerName : 
Collections.list(request.getHeaderNames())) {
+                headers.add(headerName, request.getHeader(headerName));
+            }
+
+            if (FeConstants.runningUnitTest) {
+                //remove header to avoid forward.
+                headers.remove(FORWARD_MASTER_UT_TEST);
+            }
+
+            HttpEntity<Object> entity = new HttpEntity<>(body, headers);
+
+            RestTemplate restTemplate = new RestTemplate();
+
+            ResponseEntity<Object> responseEntity;
+            switch (method) {
+                case "GET":
+                    responseEntity = restTemplate.exchange(redirectUrl, 
HttpMethod.GET, entity, Object.class);
+                    break;
+                case "POST":
+                    responseEntity = restTemplate.exchange(redirectUrl, 
HttpMethod.POST, entity, Object.class);
+                    break;
+                case "PUT":
+                    responseEntity = restTemplate.exchange(redirectUrl, 
HttpMethod.PUT, entity, Object.class);
+                    break;
+                case "DELETE":
+                    responseEntity = restTemplate.exchange(redirectUrl, 
HttpMethod.DELETE, entity, Object.class);
+                    break;
+                default:
+                    throw new UnsupportedOperationException("Unsupported HTTP 
method: " + method);
+            }
+
+            return responseEntity.getBody();
+        } catch (Exception e) {
+            LOG.warn(e);
+            return ResponseEntityBuilder.okWithCommonError(e.getMessage());
+        }
+    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/ShowAction.java 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/ShowAction.java
index 09ca16e6ad0..162e1d27ffc 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/ShowAction.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/ShowAction.java
@@ -37,7 +37,6 @@ import org.apache.doris.mysql.privilege.PrivPredicate;
 import org.apache.doris.persist.Storage;
 import org.apache.doris.qe.ConnectContext;
 
-import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
 import com.google.common.collect.Maps;
 import org.apache.commons.lang3.StringUtils;
@@ -46,7 +45,6 @@ import org.apache.logging.log4j.Logger;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.servlet.view.RedirectView;
 
 import java.io.IOException;
 import java.net.InetSocketAddress;
@@ -105,6 +103,9 @@ public class ShowAction extends RestBaseController {
     //http://username:[email protected]:8030/api/show_proc?path=/
     @RequestMapping(path = "/api/show_proc", method = RequestMethod.GET)
     public Object show_proc(HttpServletRequest request, HttpServletResponse 
response) {
+        if (needRedirect(request.getScheme())) {
+            return redirectToHttps(request);
+        }
         executeCheckPassword(request, response);
         // check authority
         checkGlobalAuth(ConnectContext.get().getCurrentUserIdentity(), 
PrivPredicate.ADMIN);
@@ -117,14 +118,8 @@ public class ShowAction extends RestBaseController {
         }
 
         // forward to master if necessary
-        if (!Env.getCurrentEnv().isMaster() && isForward) {
-            try {
-                RedirectView redirectView = 
redirectToMasterOrException(request, response);
-                Preconditions.checkNotNull(redirectView);
-                return redirectView;
-            } catch (Exception e) {
-                return ResponseEntityBuilder.okWithCommonError(e.getMessage());
-            }
+        if (checkForwardToMaster(request) && isForward) {
+            return forwardToMaster(request);
         } else {
             ProcNodeInterface procNode = null;
             ProcService instance = ProcService.getInstance();
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/manager/NodeAction.java 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/manager/NodeAction.java
index 4658f936db5..f42c09d4737 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/manager/NodeAction.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/manager/NodeAction.java
@@ -144,8 +144,12 @@ public class NodeAction extends RestBaseController {
     private Object fetchNodeInfo(HttpServletRequest request, 
HttpServletResponse response, String procPath)
             throws Exception {
         try {
-            if (!Env.getCurrentEnv().isMaster()) {
-                return redirectToMasterOrException(request, response);
+            if (needRedirect(request.getScheme())) {
+                return redirectToHttps(request);
+            }
+
+            if (checkForwardToMaster(request)) {
+                return forwardToMaster(request, null);
             }
 
             ProcResult procResult = 
ProcService.getInstance().open(procPath).fetchResult();
@@ -604,8 +608,12 @@ public class NodeAction extends RestBaseController {
     public Object operateBackend(HttpServletRequest request, 
HttpServletResponse response, @PathVariable String action,
             @RequestBody BackendReqInfo reqInfo) {
         try {
-            if (!Env.getCurrentEnv().isMaster()) {
-                return redirectToMasterOrException(request, response);
+            if (needRedirect(request.getScheme())) {
+                return redirectToHttps(request);
+            }
+
+            if (checkForwardToMaster(request)) {
+                return forwardToMaster(request, reqInfo);
             }
 
             List<String> hostPorts = reqInfo.getHostPorts();
@@ -647,8 +655,12 @@ public class NodeAction extends RestBaseController {
     public Object operateFrontends(HttpServletRequest request, 
HttpServletResponse response,
             @PathVariable String action, @RequestBody FrontendReqInfo reqInfo) 
{
         try {
-            if (!Env.getCurrentEnv().isMaster()) {
-                return redirectToMasterOrException(request, response);
+            if (needRedirect(request.getScheme())) {
+                return redirectToHttps(request);
+            }
+
+            if (checkForwardToMaster(request)) {
+                return forwardToMaster(request, reqInfo);
             }
 
             String role = reqInfo.getRole();
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/restv2/AddStoragePolicyAction.java
 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/restv2/AddStoragePolicyAction.java
index 435da3ca195..446f9f5306b 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/restv2/AddStoragePolicyAction.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/restv2/AddStoragePolicyAction.java
@@ -52,8 +52,12 @@ public class AddStoragePolicyAction extends 
RestBaseController {
         }
 
         try {
-            if (!Env.getCurrentEnv().isMaster()) {
-                return redirectToMasterOrException(request, response);
+            if (needRedirect(request.getScheme())) {
+                return redirectToHttps(request);
+            }
+
+            if (checkForwardToMaster(request)) {
+                return forwardToMaster(request, body);
             }
         } catch (Exception e) {
             return ResponseEntityBuilder.okWithCommonError(e.getMessage());
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/restv2/ESCatalogAction.java 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/restv2/ESCatalogAction.java
index 1a075c79782..aeb2591eced 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/restv2/ESCatalogAction.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/restv2/ESCatalogAction.java
@@ -55,12 +55,12 @@ public class ESCatalogAction extends RestBaseController {
             executeCheckPassword(request, response);
         }
 
-        try {
-            if (!Env.getCurrentEnv().isMaster()) {
-                return redirectToMasterOrException(request, response);
-            }
-        } catch (Exception e) {
-            return ResponseEntityBuilder.okWithCommonError(e.getMessage());
+        if (needRedirect(request.getScheme())) {
+            return redirectToHttps(request);
+        }
+
+        if (checkForwardToMaster(request)) {
+            return forwardToMaster(request);
         }
 
         Map<String, Object> resultMap = Maps.newHashMap();
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/restv2/StatisticAction.java 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/restv2/StatisticAction.java
index dcc847275c8..2b2a6d49b63 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/restv2/StatisticAction.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/restv2/StatisticAction.java
@@ -50,13 +50,12 @@ public class StatisticAction extends RestBaseController {
         if (Config.enable_all_http_auth) {
             executeCheckPassword(request, response);
         }
+        if (needRedirect(request.getScheme())) {
+            return redirectToHttps(request);
+        }
 
-        try {
-            if (!Env.getCurrentEnv().isMaster()) {
-                return redirectToMasterOrException(request, response);
-            }
-        } catch (Exception e) {
-            return ResponseEntityBuilder.okWithCommonError(e.getMessage());
+        if (checkForwardToMaster(request)) {
+            return forwardToMaster(request);
         }
 
         Map<String, Object> resultMap = Maps.newHashMap();
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/http/ForwardToMasterTest.java 
b/fe/fe-core/src/test/java/org/apache/doris/http/ForwardToMasterTest.java
new file mode 100644
index 00000000000..0ba0b894340
--- /dev/null
+++ b/fe/fe-core/src/test/java/org/apache/doris/http/ForwardToMasterTest.java
@@ -0,0 +1,233 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.http;
+
+import org.apache.doris.common.FeConstants;
+
+import okhttp3.MediaType;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.JSONValue;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ForwardToMasterTest extends DorisHttpTestCase {
+    @Test
+    public void testAddBeDropBe() throws Exception {
+        FeConstants.runningUnitTest = true;
+        String port = "48013";
+            {
+                //query backends
+                String url = "http://localhost:"; + HTTP_PORT + 
"/rest/v2/manager/node/backends";
+                Request request = new Request.Builder()
+                        .get()
+                        .addHeader("Authorization", rootAuth)
+                        .addHeader("forward_master_ut_test", "true")
+                        .url(url)
+                        .build();
+                Response response = networkClient.newCall(request).execute();
+                Assert.assertTrue(response.isSuccessful());
+                Assert.assertNotNull(response.body());
+                String respStr = response.body().string();
+                JSONObject object = (JSONObject) JSONValue.parse(respStr);
+
+                JSONObject data = (JSONObject) object.get("data");
+                JSONArray columnNames = (JSONArray) ((JSONObject) 
data.get("columnNames")).get("columnNames");
+                JSONArray rows = (JSONArray) ((JSONObject) 
data.get("rows")).get("rows");
+                int sz = columnNames.size();
+                int index = columnNames.indexOf("HeartbeatPort");
+                int existsbe = 0;
+                for (int i = 0; i < rows.size(); i += sz) {
+                    if (port.equals(rows.get(i + index).toString())) {
+                        existsbe++;
+                    }
+                }
+                Assert.assertEquals(0, existsbe);
+            }
+
+            {
+                String jsonBody = "{"
+                        + "  \"hostPorts\": [\"localhost:" + port + "\"],"
+                        + "  \"properties\": {"
+                        + "    \"key1\": \"value1\","
+                        + "    \"key2\": \"value2\""
+                        + "  }"
+                        + "}";
+
+                String url = "http://localhost:"; + HTTP_PORT + 
"/rest/v2/manager/node/ADD/be";
+                Request request = new Request.Builder()
+                        .url(url)
+                        .addHeader("Content-Type", "application/json")
+                        .addHeader("Authorization", rootAuth)
+                        .addHeader("forward_master_ut_test", "true")
+                        .post(RequestBody.create(jsonBody, 
MediaType.parse("application/json")))
+                        .build();
+                Response response = networkClient.newCall(request).execute();
+                Assert.assertTrue(response.isSuccessful());
+            }
+
+            {
+                //query be
+                String url = "http://localhost:"; + HTTP_PORT + 
"/rest/v2/manager/node/backends";
+                Request request = new Request.Builder()
+                        .get()
+                        .addHeader("Authorization", rootAuth)
+                        .addHeader("forward_master_ut_test", "true")
+                        .url(url)
+                        .build();
+                Response response = networkClient.newCall(request).execute();
+                Assert.assertTrue(response.isSuccessful());
+                Assert.assertNotNull(response.body());
+                String respStr = response.body().string();
+
+                JSONObject object = (JSONObject) JSONValue.parse(respStr);
+                JSONObject data = (JSONObject) object.get("data");
+                JSONArray columnNames = (JSONArray) ((JSONObject) 
data.get("columnNames")).get("columnNames");
+                JSONArray rows = (JSONArray) ((JSONObject) 
data.get("rows")).get("rows");
+                int sz = columnNames.size();
+                int index = columnNames.indexOf("HeartbeatPort");
+                int existsbe = 0;
+                for (int i = 0; i < rows.size(); i += sz) {
+                    if (port.equals(rows.get(i + index).toString())) {
+                        existsbe++;
+                    }
+                }
+                Assert.assertEquals(1, existsbe);
+            }
+
+            {
+                // DROP be
+                String jsonBody = "{"
+                        + "  \"hostPorts\": [\"localhost:" + port + "\"],"
+                        + "  \"properties\": {"
+                        + "    \"key1\": \"value1\","
+                        + "    \"key2\": \"value2\""
+                        + "  }"
+                        + "}";
+
+                String url = "http://localhost:"; + HTTP_PORT + 
"/rest/v2/manager/node/DROP/be";
+                Request request = new Request.Builder()
+                        .url(url)
+                        .addHeader("Content-Type", "application/json")
+                        .addHeader("Authorization", rootAuth)
+                        .addHeader("forward_master_ut_test", "true")
+                        .post(RequestBody.create(jsonBody, 
MediaType.parse("application/json")))
+                        .build();
+                Response response = networkClient.newCall(request).execute();
+                Assert.assertTrue(response.isSuccessful());
+            }
+
+            {
+                //query be
+                String url = "http://localhost:"; + HTTP_PORT + 
"/rest/v2/manager/node/backends";
+                Request request = new Request.Builder()
+                        .get()
+                        .addHeader("forward_master_ut_test", "true")
+                        .addHeader("Authorization", rootAuth)
+                        .url(url)
+                        .build();
+                Response response = networkClient.newCall(request).execute();
+                Assert.assertTrue(response.isSuccessful());
+                Assert.assertNotNull(response.body());
+                String respStr = response.body().string();
+                JSONObject object = (JSONObject) JSONValue.parse(respStr);
+
+                JSONObject data = (JSONObject) object.get("data");
+                JSONArray columnNames = (JSONArray) ((JSONObject) 
data.get("columnNames")).get("columnNames");
+                JSONArray rows = (JSONArray) ((JSONObject) 
data.get("rows")).get("rows");
+                int sz = columnNames.size();
+                int index = columnNames.indexOf("HeartbeatPort");
+                int existsbe = 0;
+                for (int i = 0; i < rows.size(); i += sz) {
+                    if (port.equals(rows.get(i + index).toString())) {
+                        existsbe++;
+                    }
+                }
+                Assert.assertEquals(0, existsbe);
+            }
+    }
+
+    @Test
+    public void testPost1() throws Exception {
+        FeConstants.runningUnitTest = true;
+        RequestBody emptyBody = RequestBody.create(new byte[0], null);
+        String url = "http://localhost:"; + HTTP_PORT + 
"/api/dbforwardmaster/_cancel?label=1";
+        Request request = new Request.Builder()
+                .url(url)
+                .addHeader("Authorization", rootAuth)
+                .addHeader("forward_master_ut_test", "true")
+                .post(emptyBody)
+                .build();
+        Response response = networkClient.newCall(request).execute();
+        Assert.assertTrue(response.isSuccessful());
+        Assert.assertNotNull(response.body());
+        String respStr = response.body().string();
+        JSONObject object = (JSONObject) JSONValue.parse(respStr);
+
+        String data = (String) object.get("data");
+        Assert.assertTrue(data.contains("does not exist"));
+    }
+
+    @Test
+    public void testPost2() throws Exception {
+        FeConstants.runningUnitTest = true;
+        String url = "http://localhost:"; + HTTP_PORT + 
"/api/colocate/group_stable";
+        RequestBody requestBody = new okhttp3.FormBody.Builder()
+                .add("group_id", "18888")
+                .add("db_id", "99999999")
+                .build();
+
+        Request request = new Request.Builder()
+                .url(url)
+                .post(requestBody)
+                .addHeader("forward_master_ut_test", "true")
+                .addHeader("Authorization", rootAuth)
+                .build();
+        Response response = networkClient.newCall(request).execute();
+        Assert.assertTrue(response.isSuccessful());
+        Assert.assertNotNull(response.body());
+        String respStr = response.body().string();
+        JSONObject object = (JSONObject) JSONValue.parse(respStr);
+
+        String data = (String) object.get("data");
+        Assert.assertTrue(data.contains("the group 99999999.18888 isn't 
exist"));
+    }
+
+    @Test
+    public void testGet1() throws Exception {
+        FeConstants.runningUnitTest = true;
+        String url = "http://localhost:"; + HTTP_PORT + 
"/rest/v2/api/cluster_overview";
+        Request request = new Request.Builder()
+                .get()
+                .addHeader("Authorization", rootAuth)
+                .addHeader("forward_master_ut_test", "true")
+                .url(url)
+                .build();
+        Response response = networkClient.newCall(request).execute();
+        Assert.assertTrue(response.isSuccessful());
+        Assert.assertNotNull(response.body());
+        String respStr = response.body().string();
+        JSONObject object = (JSONObject) JSONValue.parse(respStr);
+
+        JSONObject data = (JSONObject) object.get("data");
+        Assert.assertTrue(data.toString().contains("diskOccupancy"));
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to