Skip to content

Commit 7efa14b

Browse files
authored
feat: add circuit breaker tproxy (#28)
* feat: add circuit breaker tproxy * refactor: delete unused comment
1 parent 251089b commit 7efa14b

File tree

5 files changed

+47
-21
lines changed

5 files changed

+47
-21
lines changed

pkg/cmd/proxy/main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ func main() {
126126
}
127127

128128
{
129-
go tproxy.NewTProxy(*proxyIptablePort, faultInjectionMgr).Start()
129+
go tproxy.NewTProxy(*proxyIptablePort, faultInjectionMgr, breakerMgr).Start()
130130
}
131131

132132
serveHTTP(ctx, readyHandler)

pkg/proxy/apiserver/handler.go

-8
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ import (
5151
var (
5252
upgradeSubresources = sets.NewString("exec", "attach")
5353
enableIpTable = os.Getenv(constants.EnvIPTable) == "true"
54-
enableWebhookProxy = os.Getenv(constants.EnvEnableWebHookProxy) == "true"
5554

5655
disableCircuitBreaker = os.Getenv(constants.EnvDisableCircuitBreaker) == "true"
5756
disableFaultInjection = os.Getenv(constants.EnvDisableCircuitBreaker) == "true"
@@ -141,15 +140,9 @@ type handler struct {
141140
electionHandler leaderelection.Handler
142141
}
143142

144-
func getReqInfoStr(r *apirequest.RequestInfo) string {
145-
return fmt.Sprintf("RequestInfo: { Path: %s, APIGroup: %s, Resource: %s, Subresource: %s, Verb: %s, Namespace: %s, Name: %s, APIVersion: %s }", r.Path, r.APIGroup, r.Resource, r.Subresource, r.Verb, r.Namespace, r.Name, r.APIVersion)
146-
}
147-
148143
func (h *handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
149144
startTime := time.Now()
150145
requestInfo, ok := apirequest.RequestInfoFrom(r.Context())
151-
klog.Infof("handle http req %s", r.URL.String())
152-
klog.Infof(getReqInfoStr(requestInfo))
153146
if !ok {
154147
klog.Errorf("%s %s %s, no request info in context", r.Method, r.Header.Get("Content-Type"), r.URL)
155148
http.Error(rw, "no request info in context", http.StatusBadRequest)
@@ -216,7 +209,6 @@ func (h *handler) getURL(r *http.Request) *url.URL {
216209
u, _ := url.Parse(fmt.Sprintf("https://%s", r.Host))
217210
if !enableIpTable {
218211
u, _ = url.Parse(fmt.Sprintf(h.cfg.Host))
219-
klog.Infof("disable IPTABLE, proxy apiServer with real host %s", u.String())
220212
r.Host = ""
221213
}
222214
return u

pkg/proxy/faultinjection/manager.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ func (m *manager) doFaultInjection(faultInjections []*ctrlmeshproto.HTTPFaultInj
278278
if isInpercentRange(faultInjections[idx].Delay.Percent) {
279279
delay := faultInjections[idx].Delay.GetFixedDelay()
280280
delayDuration := delay.AsDuration()
281-
fmt.Println("Delaying for ", delayDuration)
281+
logger.Info("Delaying time ", "for", delayDuration)
282282
time.Sleep(delayDuration)
283283
}
284284
}

pkg/proxy/http/http_proxy.go

+42-10
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package http
1919
import (
2020
"encoding/json"
2121
"fmt"
22+
"os"
2223

2324
"net/http"
2425
"net/url"
@@ -27,29 +28,34 @@ import (
2728
"k8s.io/klog/v2"
2829
logf "sigs.k8s.io/controller-runtime/pkg/log"
2930

31+
"github.com/KusionStack/controller-mesh/pkg/apis/ctrlmesh/constants"
3032
meshhttp "github.com/KusionStack/controller-mesh/pkg/apis/ctrlmesh/http"
33+
"github.com/KusionStack/controller-mesh/pkg/proxy/circuitbreaker"
3134
"github.com/KusionStack/controller-mesh/pkg/proxy/faultinjection"
3235
"github.com/KusionStack/controller-mesh/pkg/utils"
3336
utilshttp "github.com/KusionStack/controller-mesh/pkg/utils/http"
3437
)
3538

3639
var (
37-
logger = logf.Log.WithName("http-proxy")
40+
enableRestBreaker = os.Getenv(constants.EnvEnableRestCircuitBreaker) == "true"
41+
logger = logf.Log.WithName("http-proxy")
3842
)
3943

4044
type ITProxy interface {
4145
Start()
4246
}
4347

4448
type tproxy struct {
45-
port int
46-
FaultInjector faultinjection.ManagerInterface
49+
port int
50+
FaultInjector faultinjection.ManagerInterface
51+
CircuitInjector circuitbreaker.ManagerInterface
4752
}
4853

49-
func NewTProxy(port int, faultInjector faultinjection.ManagerInterface) ITProxy {
54+
func NewTProxy(port int, faultInjector faultinjection.ManagerInterface, circuitInjector circuitbreaker.ManagerInterface) ITProxy {
5055
return &tproxy{
51-
port: port,
52-
FaultInjector: faultInjector,
56+
port: port,
57+
FaultInjector: faultInjector,
58+
CircuitInjector: circuitInjector,
5359
}
5460
}
5561

@@ -59,7 +65,7 @@ func (t *tproxy) Start() {
5965
Addr: fmt.Sprintf(":%d", t.port),
6066
Handler: http.HandlerFunc(t.handleHTTP),
6167
}
62-
logger.Info("%s", server.ListenAndServe())
68+
klog.Infof("%s", server.ListenAndServe())
6369
}
6470

6571
func (t *tproxy) handleHTTP(resp http.ResponseWriter, req *http.Request) {
@@ -76,9 +82,10 @@ func (t *tproxy) handleHTTP(resp http.ResponseWriter, req *http.Request) {
7682
return
7783
}
7884
realEndPointUrl = epUrl
79-
logger.Info("receive", "proxy-host", realEndPointUrl.Host, "proxy-method", req.Method, "Mesh-Real-Endpoint", realEp)
85+
klog.Infof("receive, proxy-host: %s, proxy-method: %s, Mesh-Real-Endpoint: %s", realEndPointUrl.Host, req.Method, realEp)
8086
}
81-
logger.Info("handel http request", "url", realEndPointUrl.String())
87+
klog.Infof("handel http request, url: %s ", realEndPointUrl.String())
88+
// faultinjection
8289
result := t.FaultInjector.FaultInjectionRest(req.Header.Get(meshhttp.HeaderMeshRealEndpoint), req.Method)
8390
if result.Abort {
8491
apiErr := utils.HttpToAPIError(int(result.ErrCode), req.Method, result.Message)
@@ -87,10 +94,35 @@ func (t *tproxy) handleHTTP(resp http.ResponseWriter, req *http.Request) {
8794
if err := json.NewEncoder(resp).Encode(apiErr); err != nil {
8895
http.Error(resp, fmt.Sprintf("fail to inject fault %v", err), http.StatusInternalServerError)
8996
}
90-
logger.Info("faultInjection rule", "rule", fmt.Sprintf("fault injection, %s, %s,%d", result.Reason, result.Message, result.ErrCode))
97+
klog.Infof("faultInjection rule, rule: %s", fmt.Sprintf("fault injection, %s, %s,%d", result.Reason, result.Message, result.ErrCode))
9198
return
9299
}
93100

101+
// circuitbreaker
102+
if enableRestBreaker {
103+
// check request is in the whitelist
104+
klog.Infof("start checktrafficrule %s", realEndPointUrl.Host)
105+
result := t.CircuitInjector.ValidateTrafficIntercept(realEndPointUrl.Host, req.Method)
106+
if !result.Allowed {
107+
klog.Infof("ErrorTProxy: %s %s ValidateTrafficIntercept NOPASSED ,checkresult:\t%s", realEndPointUrl.Host, req.Method, result.Reason)
108+
http.Error(resp, fmt.Sprintf("Forbidden by ValidateTrafficIntercept breaker, %s, %s", result.Message, result.Reason), http.StatusForbidden)
109+
return
110+
}
111+
}
112+
113+
// ValidateTrafficIntercept check pass or enableRestBreaker is false run http proxy
114+
klog.Infof("TProxy: %s %s ValidateTrafficIntercept check PASSED or enableRestBreaker is false", realEndPointUrl.Host, req.Method)
115+
116+
// ValidateRest check
117+
klog.Infof("start ValidateRest checkrule %s %s", realEndPointUrl.Host, req.Method)
118+
validateresult := t.CircuitInjector.ValidateRest(req.Header.Get("Mesh-Real-Endpoint"), req.Method)
119+
if !validateresult.Allowed {
120+
klog.Infof("ErrorTProxy: %s %s ValidateRest NOPASSED ,checkresult:%t, validateresultReason:%s", req.Header.Get("Mesh-Real-Endpoint"), req.Method, validateresult.Allowed, validateresult.Reason)
121+
http.Error(resp, fmt.Sprintf("Forbidden by circuit ValidateRest breaker, %s, %s", validateresult.Message, validateresult.Reason), http.StatusForbidden)
122+
return
123+
}
124+
klog.Infof("TProxy: %s %s ValidateRest check PASSED", realEndPointUrl.Host, req.Method)
125+
94126
// modify request
95127
director := func(target *http.Request) {
96128
target.Header.Set("Pass-Via-Go-TProxy", "1")

pkg/proxy/http/http_proxy_test.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626

2727
meshhttp "github.com/KusionStack/controller-mesh/pkg/apis/ctrlmesh/http"
2828
ctrlmeshproto "github.com/KusionStack/controller-mesh/pkg/apis/ctrlmesh/proto"
29+
"github.com/KusionStack/controller-mesh/pkg/proxy/circuitbreaker"
2930
"github.com/KusionStack/controller-mesh/pkg/proxy/faultinjection"
3031
)
3132

@@ -52,6 +53,7 @@ func TestTProxy(t *testing.T) {
5253

5354
func StartProxy() {
5455
faultInjectionMgr := faultinjection.NewManager(context.TODO())
56+
circuitInjectionMgr := circuitbreaker.NewManager(context.TODO())
5557
_, err := faultInjectionMgr.Sync(&ctrlmeshproto.FaultInjection{
5658
Option: ctrlmeshproto.FaultInjection_UPDATE,
5759
ConfigHash: "123",
@@ -119,6 +121,6 @@ func StartProxy() {
119121
},
120122
})
121123
utilruntime.Must(err)
122-
tProxy := NewTProxy(15002, faultInjectionMgr)
124+
tProxy := NewTProxy(15002, faultInjectionMgr, circuitInjectionMgr)
123125
tProxy.Start()
124126
}

0 commit comments

Comments
 (0)