SCB-1478 support API gateway (#73)
diff --git a/README.md b/README.md
index 567b03a..9da0058 100644
--- a/README.md
+++ b/README.md
@@ -14,11 +14,11 @@
and use mesher to make other service join to the same system.
- flexible: you can develop and customize your own service mesh
- OS: support both linux and windows OS, which means you can govern your services writen in .net with java, go etc.
-
+- API gateway: mesher is able to run as a independent edge service and manage ingress traffic.
# Features
- Build on top of go micro service framework: so that mesher has all of features of
[go chassis](https://github.com/go-chassis/go-chassis),a high flexible go micro service framework.
-you can custom your own service mesh by extending lots of components.
+you can custom your own service mesh and API gateway by extending lots of components.
- Admin API:Listen on an isolated port, expose useful runtime information and metrics.
- support protocols: http and grpc
- No IP tables forwarding: Mesher leverage
@@ -59,7 +59,6 @@
- docker image name: servicecomb/mesher-sidecar:latest
# Documentations
-# Documentations
You can see more documentations in [here](https://mesher.readthedocs.io/en/latest/),
this online doc is for latest version of mesher, if you want to see your version's doc,
follow [here](docs/README.md) to generate it in local
diff --git a/cmd/mesher/mesher.go b/cmd/mesher/mesher.go
index a1a28a5..007ff20 100644
--- a/cmd/mesher/mesher.go
+++ b/cmd/mesher/mesher.go
@@ -26,12 +26,13 @@
_ "github.com/apache/servicecomb-mesher/proxy/protocol/dubbo/client/chassis"
_ "github.com/apache/servicecomb-mesher/proxy/protocol/dubbo/server"
_ "github.com/apache/servicecomb-mesher/proxy/protocol/dubbo/simpleRegistry"
-
- _ "github.com/go-chassis/go-chassis/configcenter" //use config center
+ // config server
+ _ "github.com/go-chassis/go-chassis-config/servicecombkie"
//protocols
_ "github.com/apache/servicecomb-mesher/proxy/protocol/grpc"
_ "github.com/apache/servicecomb-mesher/proxy/protocol/http"
-
+ //ingress rule fetcher
+ _ "github.com/apache/servicecomb-mesher/proxy/ingress/servicecomb"
"github.com/apache/servicecomb-mesher/proxy/server"
_ "github.com/apache/servicecomb-mesher/proxy/pkg/egress/archaius"
diff --git a/docs/configuration.rst b/docs/configuration.rst
index 791543c..eaad50b 100644
--- a/docs/configuration.rst
+++ b/docs/configuration.rst
@@ -10,3 +10,4 @@
configurations/admin
configurations/health
configurations/destination_resolver
+ configurations/edge
diff --git a/docs/configurations/cli.md b/docs/configurations/cli.md
index 0fe6811..38c646e 100644
--- a/docs/configurations/cli.md
+++ b/docs/configurations/cli.md
@@ -13,7 +13,7 @@
**--mode**
->*(optional, string)* mesher has 2 work mode, sidecar and per-host, default is sidecar
+>*(optional, string)* mesher has 2 work mode, sidecar and edge, default is sidecar
**--service-ports**
diff --git a/docs/configurations/edge.md b/docs/configurations/edge.md
new file mode 100644
index 0000000..9076689
--- /dev/null
+++ b/docs/configurations/edge.md
@@ -0,0 +1,78 @@
+# API gateway
+mesher is able to work as a API gateway to mange traffic,to run mesher as an API gateway
+```shell
+mesher --config=mesher.yaml --mode edge
+```
+the ingress rule is in mesher.yaml
+
+### Options
+
+**mesher.ingress.type**
+>*(optional, string)* default is servicecomb, it reads servicecomb ingress rule.
+>it is a plugin, you can custom your own implementation
+
+
+**mesher.ingress.rule.http**
+>*(optional, string)* rule about how to forward http traffic. it holds a yaml content as rule.
+
+below explain the content, the rule list is like a filter, all the request will go through this rule list until match one rule.
+
+**apiPath**
+>*(required, string)* if request's url match this, it will use this rule
+
+**host**
+>*(optional, string)* if request HOST match this, mesher will use this rule, it can be empty,
+>if you set both host and apiPath, the request's host and api path must match them at the same time
+>
+**service.name**
+>*(required, string)* target backend service name in registry service(like ServiceComb service center)
+>
+**service.redirectPath**
+>*(optional, string)* by default, mesher use original request's url
+>
+**service.port.value**
+>*(optional, string)* if you use java chassis or go chassis to develop backend service, no need to set it.
+>but if your backend service use mesher-sidecar, you must give your service port here.
+>
+### example
+```yaml
+mesher:
+ ingress:
+ type: servicecomb
+ rule:
+ http: |
+ - host: example.com
+ apiPath: /some/api
+ service:
+ name: example
+ redirectPath: /another/api
+ port:
+ name: http-legacy
+ value: 8080
+ - apiPath: /some/api
+ service:
+ name: Server
+ port:
+ name: http
+ value: 8080
+```
+
+
+### Enable TLS
+generate private key
+```sh
+openssl genrsa -out server.key 2048
+```
+sign cert with private key
+```shell script
+openssl req -new -x509 -key server.key -out server.crt -days 3650
+```
+set file path in chassis.yaml
+```yaml
+ssl:
+ mesher-edge.rest.Provider.certFile: server.crt
+ mesher-edge.rest.Provider.keyFile: server.key
+```
+
+To know advanced feature about TLS configuration, check
+https://docs.go-chassis.com/user-guides/tls.html
\ No newline at end of file
diff --git a/docs/development.rst b/docs/development.rst
new file mode 100644
index 0000000..079de99
--- /dev/null
+++ b/docs/development.rst
@@ -0,0 +1,20 @@
+Development guides
+=========================
+mesher is an out of box service mesh and API gateway component,
+you can use them by simply setting configuration files.
+But some of user still need to customize a service mesh or API gateway.
+For example:
+
+- API gateway need to query account system and do the authentication and authorization.
+- mesher need to access cloud provider API
+- mesher use customized control panel
+- mesher use customized config server
+
+
+.. toctree::
+ :maxdepth: 4
+ :glob:
+
+ development/handler-chain
+ development/cloud-provider
+ development/build
diff --git a/docs/development/build.md b/docs/development/build.md
new file mode 100644
index 0000000..0454d44
--- /dev/null
+++ b/docs/development/build.md
@@ -0,0 +1,7 @@
+# Build mesher
+you need to build and release your mesher after the customization
+
+### Build binary
+you can refer to build/build_proxy to see how we build mesher binary and docker image.
+
+build/docker/proxy/Dockerfile is a example about how to make a docker image
\ No newline at end of file
diff --git a/docs/development/cloud-provider.md b/docs/development/cloud-provider.md
new file mode 100644
index 0000000..f464ac8
--- /dev/null
+++ b/docs/development/cloud-provider.md
@@ -0,0 +1,33 @@
+# Cloud Provider
+By default Mesher do not support any cloud provider.
+But there is plugin that helps mesher to do it.
+
+### Huawei Cloud
+Mesher is able to use huawei cloud ServiceComb engine.
+#### Access ServiceComb Engine API
+import auth in cmd/mesher/mesher.go
+```go
+import _ "github.com/huaweicse/auth/adaptor/gochassis"
+```
+
+it will sign all requests between mesher to ServiceComb Engine.
+
+#### Use Config Center to manage configuration
+Mesher use servicecomb-kie as config server,
+```go
+_ "github.com/go-chassis/go-chassis-config/servicecombkie"
+```
+when you need to use ServiceComb Engine, you must replace this line.
+import config center in cmd/mesher/mesher.go.
+```go
+_ "github.com/go-chassis/go-chassis-config/configcenter"
+```
+set the config center in chassis.yaml
+```yaml
+ config:
+ client:
+ serverUri: https://xxx #endpoint of servicecomb engine
+ refreshMode: 1 # 1: only pull config.
+ refreshInterval: 30 # unit is second
+ type: config_center
+```
\ No newline at end of file
diff --git a/docs/development/handler-chain.md b/docs/development/handler-chain.md
new file mode 100644
index 0000000..4960583
--- /dev/null
+++ b/docs/development/handler-chain.md
@@ -0,0 +1,42 @@
+# Handler chain
+all the traffic will go through the handler chain.
+A chain is composite of handlers, each handler has a particular logic.
+Mesher also has a lots of feature working in chain, like route management, circuit breaking, rate-limiting.
+In Summary, handler is the middle ware between client and servers,
+it is useful, when you want to add authorization to intercept illegal requests.
+
+### How to write a handler
+https://docs.go-chassis.com/dev-guides/how-to-implement-handler.html
+
+### How to use it in handler chain
+in chassis.yaml add your handler name in chain configuration.
+as side car and API gateway, mesher's chain has different meaning.
+
+For example, running as mesher-sidecar, service A call another service B,
+outgoing chain process all the service A requests before remote call,
+incoming chain process all the requests from service A, before access to service B API.
+
+In summary outgoing chain works when a service attempt to call other services,
+incoming chain works when other services call this service
+```yaml
+ handler:
+ chain:
+ Consumer:
+ # if a service call other service, it go through this chain, loadbalance and transport is must
+ outgoing: router, bizkeeper-consumer, loadbalance, transport
+ Provider:
+ incoming: ratelimiter-provider
+```
+
+running as API gateway,
+incoming chain process all the requests from the external network,
+outgoing chain process all the the request between API gateway and backend services
+```yaml
+ handler:
+ chain:
+ Consumer:
+ #loadbalance and transport is must
+ outgoing: router, bizkeeper-consumer, loadbalance, transport
+ Provider:
+ incoming: ratelimiter-provider
+```
\ No newline at end of file
diff --git a/docs/index.rst b/docs/index.rst
index 17e0a0c..09187fc 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -13,6 +13,7 @@
intro
get-started
configuration
+ development
protocols
istio-guides
sidecar
diff --git a/examples/edge/conf/chassis.yaml b/examples/edge/conf/chassis.yaml
new file mode 100644
index 0000000..0ab8bd4
--- /dev/null
+++ b/examples/edge/conf/chassis.yaml
@@ -0,0 +1,78 @@
+---
+cse:
+ protocols:
+ http:
+ listenAddress: 127.0.0.1:30101
+ rest-admin:
+ listenAddress: 127.0.0.1:30102 # listen addr use to adminAPI
+ service:
+ registry:
+ address: http://127.0.0.1:30100 # uri of service center
+ #address: https://cse.cn-north-1.myhuaweicloud.com:443 # uri of service center
+ scope: full #set full to be able to discover other app's service
+ watch: false # set if you want to watch instance change event
+ autoIPIndex: true # set to true if u want to resolve source IP to micro service
+# config:
+# client:
+# serverUri: https://127.0.0.1:30110 #uri of config center
+# type: servicecomb-kie
+# refreshMode: 1 # 1: only pull config.
+# refreshInterval: 30 # unit is second
+ # monitor: #Send monitoring data to CSE monitor Server
+ # client:
+ # serverUri: https://cse.cn-north-1.myhuaweicloud.com:443 # monitor server url
+ handler:
+ chain:
+ Consumer:
+ outgoing: router,bizkeeper-consumer,loadbalance,tracing-consumer,transport #consumer handlers
+ Provider:
+ incoming: tracing-provider #provider handlers
+# loadbalance:
+# strategy:
+# name: RoundRobin # Random|RoundRobin|SessionStickiness
+# retryEnabled: false # if there is error, retry request or not
+# retryOnNext: 2 # times to switch to another instance based on strategy
+# retryOnSame: 3 # times to retry on the same instance
+# backoff: # backoff policy of retried request
+# kind: constant # jittered/constant/zero
+# MinMs: 200 # millisecond, Minimum duration to backoff
+# MaxMs: 400 # millisecond, Maximum duration to backoff
+## circuit breaker configurations
+# isolation:
+# Consumer:
+# timeout:
+# enabled: true
+# timeoutInMilliseconds: 1000
+# maxConcurrentRequests: 100
+# circuitBreaker:
+# Consumer:
+# enabled: true
+# forceOpen: false
+# forceClosed: false
+# sleepWindowInMilliseconds: 10000
+# requestVolumeThreshold: 20
+# errorThresholdPercentage: 50
+# fallback:
+# Consumer:
+# enabled: true
+# maxConcurrentRequests: 20
+# fallbackpolicy:
+# Consumer:
+# policy: throwexception
+
+## Mesher TLS is base on Go Chassis TLS config
+ssl:
+# mesher-edge.rest.Provider.cipherPlugin: default
+# mesher-edge.rest.Provider.verifyPeer: false
+# mesher-edge.rest.Provider.cipherSuits: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+# mesher-edge.rest.Provider.protocol: TLSv1.2
+# mesher-edge.rest.Provider.caFile:
+ mesher-edge.rest.Provider.certFile: server.crt
+ mesher-edge.rest.Provider.keyFile: server.key
+# mesher-edge.rest.Provider.certPwdFile:
+
+#tracing:
+# enabled: true #enable distribution tracing
+# collectorType: zipkin #zipkin: Send tracing info to zipkin server
+# #namedPipe: Write tracing info to linux named pipe.
+# collectorTarget: http://localhost:9411/api/v1/spans #If the collectorType is "zipkin", the target is a zipkin server url, if the collecterType is "file" or "namedPipe", the target is a file path.
diff --git a/examples/edge/conf/mesher.yaml b/examples/edge/conf/mesher.yaml
new file mode 100644
index 0000000..55aa97f
--- /dev/null
+++ b/examples/edge/conf/mesher.yaml
@@ -0,0 +1,52 @@
+## Router rules and fault injection rules are moved to router.yaml
+#plugin:
+# destinationResolver:
+# http: host # how to turn host to destination name. default to service name,
+
+admin: #admin API
+ goRuntimeMetrics : true # enable metrics
+ enable: true
+
+## enable pprof to profile mesher runtime
+#pprof:
+# enable: false
+
+
+# this health check will ping local service port to check if service is still alive, if service can not reachable, mesher
+# will update status to OUT_OF_SERVICE in service center
+#localHealthCheck:
+# - port: 8080
+# uri: /health
+# interval: 30s
+# match:
+# status: 200
+# body: ok
+
+
+mesher:
+ ingress:
+ type: servicecomb
+ rule:
+ http: |
+ - host: example.com
+ limit: 30
+ apiPath: /some/api
+ service:
+ name: example
+ redirectPath: /another/api
+ port:
+ name: http-legacy
+ value: 8080
+ - apiPath: /sayerror/api
+ service:
+ name: Server
+ redirectPath: /sayerror
+ port:
+ name: http
+ value: 8080
+ - apiPath: /some/api
+ service:
+ name: Server
+ port:
+ name: http
+ value: 8080
\ No newline at end of file
diff --git a/examples/edge/conf/microservice.yaml b/examples/edge/conf/microservice.yaml
new file mode 100644
index 0000000..8103479
--- /dev/null
+++ b/examples/edge/conf/microservice.yaml
@@ -0,0 +1,3 @@
+service_description:
+ name: mesher-edge
+ version: 0.0.1
diff --git a/go.mod b/go.mod
index b0bb0ae..addfe9b 100644
--- a/go.mod
+++ b/go.mod
@@ -2,20 +2,22 @@
require (
github.com/Shopify/toxiproxy v2.1.3+incompatible // indirect
+ github.com/apache/servicecomb-kie v0.1.0 // indirect
github.com/emicklei/go-restful-swagger12 v0.0.0-20170926063155-7524189396c6 // indirect
github.com/envoyproxy/go-control-plane v0.6.0
- github.com/ghodss/yaml v1.0.0 // indirect
+ github.com/ghodss/yaml v1.0.0
github.com/go-chassis/foundation v0.0.0-20190621030543-c3b63f787f4c
github.com/go-chassis/go-archaius v0.20.0
- github.com/go-chassis/go-chassis v1.6.1
+ github.com/go-chassis/go-chassis v1.7.1-0.20190903133217-e4a22c998fe1
+ github.com/go-chassis/go-chassis-config v0.10.0
github.com/go-chassis/gohessian v0.0.0-20180702061429-e5130c25af55
- github.com/go-mesh/openlogging v1.0.0
+ github.com/go-logfmt/logfmt v0.4.0 // indirect
+ github.com/go-mesh/openlogging v1.0.1-0.20181205082104-3d418c478b2d
github.com/gogo/googleapis v1.1.0 // indirect
github.com/gogo/protobuf v1.2.0
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf // indirect
github.com/imdario/mergo v0.3.6 // indirect
github.com/lyft/protoc-gen-validate v0.0.11 // indirect
- github.com/onsi/gomega v1.4.2 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/prometheus/client_golang v0.9.1
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f
@@ -23,7 +25,6 @@
github.com/stretchr/testify v1.3.0
github.com/uber-go/atomic v1.3.2 // indirect
github.com/urfave/cli v1.20.1-0.20181029213200-b67dcf995b6a
- go.uber.org/atomic v1.3.2 // indirect
golang.org/x/net v0.0.0-20190311183353-d8887717615a
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2 // indirect
google.golang.org/grpc v1.16.0
diff --git a/proxy/bootstrap/bootstrap.go b/proxy/bootstrap/bootstrap.go
index 431613c..09b5872 100644
--- a/proxy/bootstrap/bootstrap.go
+++ b/proxy/bootstrap/bootstrap.go
@@ -82,20 +82,21 @@
//DecideMode get config mode
func DecideMode() error {
- runtime.Mode = cmd.Configs.Mode
- openlogging.GetLogger().Info("Running as " + runtime.Mode)
+ runtime.Role = cmd.Configs.Role
+ openlogging.GetLogger().Info("Running as " + runtime.Role)
return nil
}
//RegisterFramework registers framework
func RegisterFramework() {
- if framework := metadata.NewFramework(); cmd.Configs.Mode == common.ModeSidecar {
- version := GetVersion()
+ version := GetVersion()
+ if framework := metadata.NewFramework(); cmd.Configs.Role == common.RoleSidecar {
framework.SetName("Mesher")
framework.SetVersion(version)
framework.SetRegister("SIDECAR")
- } else if cmd.Configs.Mode == common.ModePerHost {
+ } else {
framework.SetName("Mesher")
+ framework.SetVersion(version)
}
}
diff --git a/proxy/cmd/cmd.go b/proxy/cmd/cmd.go
index 5fe043a..b0bb140 100644
--- a/proxy/cmd/cmd.go
+++ b/proxy/cmd/cmd.go
@@ -33,7 +33,7 @@
//ConfigFromCmd store cmd params
type ConfigFromCmd struct {
ConfigFile string
- Mode string
+ Role string
LocalServicePorts string
PortsMap map[string]string
}
@@ -54,10 +54,10 @@
},
cli.StringFlag{
Name: "mode",
- Value: common.ModeSidecar,
- Usage: fmt.Sprintf("mesher running mode [ %s|%s|%s ]",
- common.ModePerHost, common.ModeSidecar, common.ModeIngress),
- Destination: &Configs.Mode,
+ Value: common.RoleSidecar,
+ Usage: fmt.Sprintf("mesher role [ %s|%s|%s ]",
+ common.RolePerHost, common.RoleSidecar, common.RoleEdge),
+ Destination: &Configs.Role,
},
cli.StringFlag{
Name: "service-ports",
diff --git a/proxy/common/common.go b/proxy/common/common.go
index 4eaf3b0..04b536f 100644
--- a/proxy/common/common.go
+++ b/proxy/common/common.go
@@ -32,14 +32,14 @@
//ComponentName is contant for component name
const ComponentName = "mesher"
-//ModeSidecar is constant for side car mode
-const ModeSidecar = "sidecar"
+//RoleSidecar is constant for side car mode
+const RoleSidecar = "sidecar"
-//ModeIngress run as a api gateway, or ingress in k8s
-const ModeIngress = "ingress"
+//RoleEdge run as a edge service, or ingress in k8s
+const RoleEdge = "edge"
-//ModePerHost is constant for side car mode
-const ModePerHost = "per-host"
+//RolePerHost is constant for side car mode
+const RolePerHost = "per-host"
//Constants for env specific addr and service ports
const (
diff --git a/proxy/config/config.go b/proxy/config/config.go
index 1f797be..ac3143d 100644
--- a/proxy/config/config.go
+++ b/proxy/config/config.go
@@ -18,6 +18,10 @@
package config
import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+
"github.com/apache/servicecomb-mesher/proxy/cmd"
"github.com/apache/servicecomb-mesher/proxy/common"
"github.com/go-chassis/go-archaius"
@@ -28,9 +32,6 @@
"github.com/go-chassis/go-chassis/pkg/util/fileutil"
"github.com/go-mesh/openlogging"
"gopkg.in/yaml.v2"
- "io/ioutil"
- "os"
- "path/filepath"
)
//Constant for mesher conf file
@@ -88,6 +89,16 @@
//Init reads config and initiates
func Init() error {
mesherConfig = &MesherConfig{}
+ egressConfig = &EgressConfig{}
+ p, err := GetConfigFilePath(ConfFile)
+ if err != nil {
+ return err
+ }
+ err = archaius.AddFile(p)
+ if err != nil {
+ return err
+ }
+
contents, err := GetConfigContents(ConfFile)
if err != nil {
return err
@@ -96,7 +107,6 @@
return err
}
- egressConfig = &EgressConfig{}
egressContents, err := GetConfigContents(EgressConfFile)
if err != nil {
return err
diff --git a/proxy/config/struct.go b/proxy/config/struct.go
index c551953..d4d5914 100644
--- a/proxy/config/struct.go
+++ b/proxy/config/struct.go
@@ -19,6 +19,7 @@
//MesherConfig has all mesher config
type MesherConfig struct {
+ Mesher Mesher `yaml:"mesher"`
PProf *PProf `yaml:"pprof"`
Plugin *Plugin `yaml:"plugin"`
Admin Admin `yaml:"admin"`
diff --git a/proxy/config/struct_ingress.go b/proxy/config/struct_ingress.go
new file mode 100644
index 0000000..0f90f7b
--- /dev/null
+++ b/proxy/config/struct_ingress.go
@@ -0,0 +1,77 @@
+/*
+ * 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 config
+
+import (
+ "github.com/go-chassis/foundation/string"
+ "gopkg.in/yaml.v2"
+)
+
+//Mesher is prefix
+type Mesher struct {
+ Ingress Ingress `yaml:"ingress"`
+}
+
+//Ingress hold rules and other settings
+type Ingress struct {
+ Rule map[string]string `yaml:"rule"`
+ Type string `yaml:"type"`
+}
+
+//IngressRules is ingress rules slice
+type IngressRules []*IngressRule
+
+//Len return the length of rule
+func (r IngressRules) Len() int {
+ return len(r)
+}
+
+//Value return the rule
+func (r IngressRules) Value() []*IngressRule {
+ return r
+}
+
+//NewRules create a rule by raw data
+func NewRules(raw string) (*IngressRules, error) {
+ b := stringutil.Str2bytes(raw)
+ r := &IngressRules{}
+ err := yaml.Unmarshal(b, r)
+ return r, err
+}
+
+//IngressRule is a ingress rule
+type IngressRule struct {
+ Host string `yaml:"host"`
+ Limit int `yaml:"limit"`
+ APIPath string `yaml:"apiPath"`
+ Service Service `yaml:"service"`
+}
+
+//Service is upstream info
+type Service struct {
+ Name string `yaml:"name"`
+ Tags map[string]string `yaml:"tags"`
+ RedirectPath string `yaml:"redirectPath"`
+ Port Port `yaml:"port"`
+}
+
+//Port is service port information
+type Port struct {
+ Name string `yaml:"name"`
+ Value string `yaml:"value"`
+}
diff --git a/proxy/config/struct_ingress_test.go b/proxy/config/struct_ingress_test.go
new file mode 100644
index 0000000..22d268e
--- /dev/null
+++ b/proxy/config/struct_ingress_test.go
@@ -0,0 +1,62 @@
+/*
+ * 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 config_test
+
+import (
+ "github.com/apache/servicecomb-mesher/proxy/config"
+ "github.com/ghodss/yaml"
+ "github.com/stretchr/testify/assert"
+ "testing"
+)
+
+func TestNewRules(t *testing.T) {
+ b := []byte(`
+mesher:
+ ingress:
+ type: servicecomb
+ rule:
+ http: |
+ - host: example.com
+ limit: 30
+ apiPath: /some/api
+ service:
+ name: example
+ tags:
+ version: 1.0.0
+ redirectPath: /another/api
+ port:
+ name: http-legacy
+ value: 8080
+ - host: foo.com
+ apiPath: /some/api
+ service:
+ name: foo
+ tags:
+ version: 1.0.0
+ redirectPath: /another/api
+ port:
+ name: http
+ value: 8080
+`)
+ c := &config.MesherConfig{}
+ err := yaml.Unmarshal(b, c)
+ assert.NoError(t, err)
+ rules, err := config.NewRules(c.Mesher.Ingress.Rule["http"])
+ assert.NoError(t, err)
+ assert.Equal(t, 2, rules.Len())
+}
diff --git a/proxy/ingress/ingress.go b/proxy/ingress/ingress.go
new file mode 100644
index 0000000..916c4c2
--- /dev/null
+++ b/proxy/ingress/ingress.go
@@ -0,0 +1,56 @@
+/*
+ * 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 ingress
+
+import (
+ "errors"
+ "fmt"
+ "github.com/apache/servicecomb-mesher/proxy/config"
+ "github.com/go-chassis/go-archaius"
+)
+
+//error in ingress package
+var (
+ ErrNotMatch = errors.New("no matching rule")
+)
+var plugin = make(map[string]func() (RuleFetcher, error))
+
+//RuleFetcher query ingress rule
+type RuleFetcher interface {
+ Fetch(protocol, host, apiPath string, headers map[string][]string) (*config.IngressRule, error)
+}
+
+//DefaultFetcher fetch config
+var DefaultFetcher RuleFetcher
+
+//InstallPlugin install implementation
+func InstallPlugin(name string, f func() (RuleFetcher, error)) {
+ plugin[name] = f
+}
+
+//Init initialize
+func Init() error {
+ t := archaius.GetString("mesher.ingress.type", "servicecomb")
+ f, ok := plugin[t]
+ if !ok {
+ return fmt.Errorf("do not support [%s]", t)
+ }
+ var err error
+ DefaultFetcher, err = f()
+ return err
+}
diff --git a/proxy/ingress/servicecomb/ingress.go b/proxy/ingress/servicecomb/ingress.go
new file mode 100644
index 0000000..c251ca5
--- /dev/null
+++ b/proxy/ingress/servicecomb/ingress.go
@@ -0,0 +1,78 @@
+/*
+ * 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 servicecomb
+
+import (
+ "github.com/apache/servicecomb-mesher/proxy/config"
+ "github.com/apache/servicecomb-mesher/proxy/ingress"
+ "github.com/go-chassis/go-archaius"
+ "github.com/patrickmn/go-cache"
+ "regexp"
+ "time"
+)
+
+const (
+ cacheTTL = 30
+ ingressRuleKey = "mesher.ingress.rule.http"
+)
+
+var rulesData []*config.IngressRule
+
+//IngressRuleFetcher query ingress rule
+type IngressRuleFetcher struct {
+ cache *cache.Cache
+}
+
+//Fetch get ingress rule
+func (f *IngressRuleFetcher) Fetch(protocol, host, apiPath string, headers map[string][]string) (*config.IngressRule, error) {
+ for _, r := range rulesData {
+ if r.Host != "" && host != r.Host {
+ //do not match host,then ignore path
+ continue
+ }
+ match, err := regexp.MatchString(r.APIPath, apiPath)
+ if err != nil {
+ return nil, err
+ }
+ if match {
+ return r, nil
+ }
+ }
+ return nil, ingress.ErrNotMatch
+}
+
+func newFetcher() (ingress.RuleFetcher, error) {
+ raw := archaius.GetString(ingressRuleKey, "")
+ rules, err := config.NewRules(raw)
+ if err != nil {
+ return nil, err
+ }
+
+ err = archaius.RegisterListener(&ingressRuleEventListener{}, ingressRuleKey)
+ if err != nil {
+ return nil, err
+ }
+ rulesData = rules.Value()
+ return &IngressRuleFetcher{
+ cache: cache.New(cacheTTL*time.Second, 0),
+ }, nil
+}
+
+func init() {
+ ingress.InstallPlugin("servicecomb", newFetcher)
+}
diff --git a/proxy/ingress/servicecomb/listener.go b/proxy/ingress/servicecomb/listener.go
new file mode 100644
index 0000000..a1cc7b8
--- /dev/null
+++ b/proxy/ingress/servicecomb/listener.go
@@ -0,0 +1,72 @@
+/*
+ * 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 servicecomb
+
+import (
+ "github.com/apache/servicecomb-mesher/proxy/config"
+ "github.com/go-chassis/go-archaius/core"
+ "github.com/go-chassis/go-chassis/core/common"
+ "github.com/go-mesh/openlogging"
+)
+
+type ingressRuleEventListener struct{}
+
+//Event update ingress rule
+func (r *ingressRuleEventListener) Event(e *core.Event) {
+ if e == nil {
+ openlogging.Warn("Event pointer is nil")
+ return
+ }
+ openlogging.Info("dark launch event", openlogging.WithTags(openlogging.Tags{
+ "key": e.Key,
+ "event": e.EventType,
+ "rule": e.Value,
+ }))
+ raw, ok := e.Value.(string)
+ if !ok {
+ openlogging.Error("invalid ingress rule", openlogging.WithTags(openlogging.Tags{
+ "value": raw,
+ }))
+ }
+ switch e.EventType {
+ case common.Update:
+ saveRules(raw)
+ case common.Create:
+ saveRules(raw)
+ case common.Delete:
+ rulesData = nil
+ openlogging.Info("ingress rule is removed", openlogging.WithTags(
+ openlogging.Tags{
+ "key": e.Key,
+ }))
+ }
+
+}
+
+func saveRules(raw string) {
+ rules, err := config.NewRules(raw)
+ if err != nil {
+ openlogging.Error("invalid ingress rule", openlogging.WithTags(openlogging.Tags{
+ "value": raw,
+ }))
+ }
+ rulesData = rules.Value()
+ openlogging.Info("update ingress rule", openlogging.WithTags(openlogging.Tags{
+ "value": raw,
+ }))
+}
diff --git a/proxy/pkg/egress/egress_test.go b/proxy/pkg/egress/egress_test.go
index e49d395..a1c9a03 100644
--- a/proxy/pkg/egress/egress_test.go
+++ b/proxy/pkg/egress/egress_test.go
@@ -19,7 +19,11 @@
import (
"fmt"
+ "github.com/go-chassis/go-chassis/pkg/util/fileutil"
+ "github.com/stretchr/testify/assert"
+ "io"
"os"
+ "path/filepath"
"testing"
"github.com/apache/servicecomb-mesher/proxy/cmd"
@@ -36,9 +40,21 @@
func BenchmarkMatch(b *testing.B) {
lager.Initialize("", "DEBUG", "",
"size", true, 1, 10, 7)
-
- gopath := os.Getenv("GOPATH")
- os.Setenv("CHASSIS_HOME", gopath+"/src/github.com/apache/servicecomb-mesher")
+ chassis := []byte(`
+cse:
+ service:
+ registry:
+ #disabled: false optional:禁用注册发现选项,默认开始注册发现
+ type: servicecenter #optional:可选zookeeper/servicecenter,zookeeper供中软使用,不配置的情况下默认为servicecenter
+ scope: full #optional:scope不为full时,只允许在本app间访问,不允许跨app访问;为full就是注册时允许跨app,并且发现本租户全部微服务
+ address: http://127.0.0.1:30100
+ #register: manual optional:register不配置时默认为自动注册,可选参数有自动注册auto和手动注册manual
+
+`)
+ d, _ := os.Getwd()
+ filename1 := filepath.Join(d, "chassis.yaml")
+ f1, err := os.OpenFile(filename1, os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0666)
+ _, err = f1.Write(chassis)
cmd.Init()
config.Init()
mesherconfig.Init()
@@ -68,7 +84,7 @@
protocol: HTTP`
ss := mesherconfig.EgressConfig{}
- err := yaml.Unmarshal([]byte(yamlContent), &ss)
+ err = yaml.Unmarshal([]byte(yamlContent), &ss)
if err != nil {
fmt.Println("unmarshal failed")
}
@@ -84,12 +100,44 @@
lager.Initialize("", "DEBUG", "",
"size", true, 1, 10, 7)
- gopath := os.Getenv("GOPATH")
- os.Setenv("CHASSIS_HOME", gopath+"/src/github.com/apache/servicecomb-mesher")
+ b := []byte(`
+cse:
+ service:
+ registry:
+ #disabled: false optional:禁用注册发现选项,默认开始注册发现
+ type: servicecenter #optional:可选zookeeper/servicecenter,zookeeper供中软使用,不配置的情况下默认为servicecenter
+ scope: full #optional:scope不为full时,只允许在本app间访问,不允许跨app访问;为full就是注册时允许跨app,并且发现本租户全部微服务
+ address: http://127.0.0.1:30100
+ #register: manual optional:register不配置时默认为自动注册,可选参数有自动注册auto和手动注册manual
+
+`)
+ d, _ := os.Getwd()
+ filename1 := filepath.Join(d, "chassis.yaml")
+ f1, err := os.OpenFile(filename1, os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0666)
+ assert.NoError(t, err)
+ _, err = f1.Write(b)
+ b = []byte(`
+---
+#微服务的私有属性
+#APPLICATION_ID: CSE #optional
+service_description:
+ name: Client
+ #version: 0.1 #optional
+
+`)
+ d, _ = os.Getwd()
+ filename1 = filepath.Join(d, "microservice.yaml")
+ os.Remove(filename1)
+ f1, err = os.Create(filename1)
+ assert.NoError(t, err)
+ defer f1.Close()
+ _, err = io.WriteString(f1, string(b))
+ assert.NoError(t, err)
+ os.Setenv(fileutil.ChassisConfDir, d)
cmd.Init()
- config.Init()
- mesherconfig.Init()
- egress.Init()
+ err = config.Init()
+ err = mesherconfig.Init()
+ err = egress.Init()
//control.Init()
var yamlContent = `---
egress:
@@ -111,20 +159,20 @@
protocol: HTTP`
ss := mesherconfig.EgressConfig{}
- err := yaml.Unmarshal([]byte(yamlContent), &ss)
+ err = yaml.Unmarshal([]byte(yamlContent), &ss)
if err != nil {
fmt.Println("unmarshal failed")
}
archaius.SetEgressRule(ss.Destinations)
myString := "www.google.com"
- b, _ := egress.Match(myString)
- if b == false {
+ c, _ := egress.Match(myString)
+ if c == false {
t.Errorf("Expected true but got false")
}
myString = "*.yahoo.com"
- b, _ = egress.Match(myString)
- if b == false {
+ c, _ = egress.Match(myString)
+ if c == false {
t.Errorf("Expected true but got false")
}
}
diff --git a/proxy/pkg/runtime/runtime.go b/proxy/pkg/runtime/runtime.go
index 56a14bc..8a511df 100644
--- a/proxy/pkg/runtime/runtime.go
+++ b/proxy/pkg/runtime/runtime.go
@@ -18,6 +18,6 @@
package runtime
var (
- //Mode is of type string which gives mode of mesher deployment
- Mode string
+ //Role is of type string which gives mode of mesher deployment
+ Role string
)
diff --git a/proxy/protocol/dubbo/proxy/dubbo_proxy_ouput.go b/proxy/protocol/dubbo/proxy/dubbo_proxy_ouput.go
index 687b32d..571b19e 100755
--- a/proxy/protocol/dubbo/proxy/dubbo_proxy_ouput.go
+++ b/proxy/protocol/dubbo/proxy/dubbo_proxy_ouput.go
@@ -226,7 +226,7 @@
ctx.Req.SetAttachment(common.HeaderSourceName, chassisconfig.SelfServiceName)
ctx.Req.SetAttachment(ProxyTag, "true")
- if mesherRuntime.Mode == mesherCommon.ModeSidecar {
+ if mesherRuntime.Role == mesherCommon.RoleSidecar {
c, err = handler.GetChain(common.Consumer, mesherCommon.ChainConsumerOutgoing)
if err != nil {
openlogging.Error("Get Consumer chain failed: " + err.Error())
@@ -330,12 +330,12 @@
h[k] = req.Header.Get(k)
}
//Resolve Destination
- _, err = dr.Resolve(source, h, inv.URLPathFormat, &inv.MicroServiceName)
+ destination, _, err := dr.Resolve(source, "", inv.URLPathFormat, h)
if err != nil {
return err
}
-
- if mesherRuntime.Mode == mesherCommon.ModeSidecar {
+ inv.MicroServiceName = destination
+ if mesherRuntime.Role == mesherCommon.RoleSidecar {
c, err = handler.GetChain(common.Consumer, mesherCommon.ChainConsumerOutgoing)
if err != nil {
lager.Logger.Error("Get chain failed: " + err.Error())
diff --git a/proxy/protocol/grpc/reverse_proxy.go b/proxy/protocol/grpc/reverse_proxy.go
index 6da6843..3cc62a2 100755
--- a/proxy/protocol/grpc/reverse_proxy.go
+++ b/proxy/protocol/grpc/reverse_proxy.go
@@ -106,12 +106,12 @@
if r.URL.Host == "" {
r.URL.Host = r.Host
}
- port, err := dr.Resolve(source, h, r.URL.String(), &inv.MicroServiceName)
+ serviceName, port, err := dr.Resolve(source, "", r.URL.String(), h)
if err != nil {
WriteErrorResponse(inv, w, r, http.StatusBadRequest, err)
return
}
-
+ inv.MicroServiceName = serviceName
if port != "" {
h[XForwardedPort] = port
}
diff --git a/proxy/protocol/grpc/server.go b/proxy/protocol/grpc/server.go
index c51f191..435a477 100644
--- a/proxy/protocol/grpc/server.go
+++ b/proxy/protocol/grpc/server.go
@@ -72,10 +72,10 @@
return fmt.Errorf("only support ipv4, input is [%s]", hs.opts.Address)
}
- switch runtime.Mode {
- case common.ModeSidecar:
+ switch runtime.Role {
+ case common.RoleSidecar:
err = hs.startSidecar(host, port)
- case common.ModePerHost:
+ default:
err = hs.startPerHost()
}
diff --git a/proxy/protocol/http/gateway.go b/proxy/protocol/http/gateway.go
new file mode 100644
index 0000000..ff8f173
--- /dev/null
+++ b/proxy/protocol/http/gateway.go
@@ -0,0 +1,107 @@
+/*
+ * 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 http
+
+import (
+ "github.com/apache/servicecomb-mesher/proxy/common"
+ "github.com/apache/servicecomb-mesher/proxy/ingress"
+ "github.com/go-chassis/go-chassis/client/rest"
+ chassiscommon "github.com/go-chassis/go-chassis/core/common"
+ "github.com/go-chassis/go-chassis/core/handler"
+ "github.com/go-chassis/go-chassis/core/invocation"
+ "github.com/go-mesh/openlogging"
+ "net/http"
+)
+
+func handleIncomingTraffic(inv *invocation.Invocation) (*invocation.Response, error) {
+ c, err := handler.GetChain(chassiscommon.Provider, common.ChainProviderIncoming)
+ if err != nil {
+ openlogging.Error("Get chain failed: " + err.Error())
+ return nil, err
+ }
+ var invRsp *invocation.Response
+ c.Next(inv, func(ir *invocation.Response) error {
+ invRsp = ir
+ if invRsp != nil {
+ return invRsp.Err
+ }
+ return nil
+ })
+ return invRsp, nil
+}
+
+//HandleIngressTraffic is api gateway http handler
+func HandleIngressTraffic(w http.ResponseWriter, r *http.Request) {
+ inv := &invocation.Invocation{}
+ inv.Reply = rest.NewResponse()
+ inv.Protocol = "rest"
+ h := make(map[string]string)
+ for k := range r.Header {
+ h[k] = r.Header.Get(k)
+ }
+ inv.Ctx = chassiscommon.NewContext(h)
+ invResp, err := handleIncomingTraffic(inv)
+ if err != nil {
+ handleErrorResponse(inv, w, http.StatusInternalServerError, err)
+ return
+ }
+ if invResp != nil {
+ if invResp.Status != 0 || invResp.Err != nil {
+ handleErrorResponse(inv, w, invResp.Status, invResp.Err)
+ return
+ }
+ }
+ rule, err := ingress.DefaultFetcher.Fetch("http", r.Host, r.URL.Path, r.Header)
+ if err != nil {
+ handleErrorResponse(inv, w, http.StatusInternalServerError, err)
+ return
+ }
+ inv.MicroServiceName = rule.Service.Name
+ targetAPI := r.URL.Path
+ if rule.Service.RedirectPath != "" {
+ targetAPI = rule.Service.RedirectPath
+ }
+ newReq, err := http.NewRequest(r.Method, "http://"+inv.MicroServiceName+targetAPI, r.Body)
+ if err != nil {
+ handleErrorResponse(inv, w, http.StatusInternalServerError, err)
+ return
+ }
+ inv.Args = newReq
+ h[XForwardedPort] = rule.Service.Port.Value
+ c, err := handler.GetChain(chassiscommon.Consumer, common.ChainConsumerOutgoing)
+ if err != nil {
+ handleErrorResponse(inv, w, http.StatusBadGateway, err)
+ openlogging.Error("Get chain failed: " + err.Error())
+ return
+ }
+ var invRsp *invocation.Response
+ c.Next(inv, func(ir *invocation.Response) error {
+ //Send the request to the destination
+ invRsp = ir
+ if invRsp != nil {
+ return invRsp.Err
+ }
+ return nil
+ })
+ resp, err := handleRequest(w, inv, invRsp)
+ if err != nil {
+ openlogging.Error("Handle request failed: " + err.Error())
+ return
+ }
+ RecordStatus(inv, resp.StatusCode)
+}
diff --git a/proxy/protocol/http/http_server.go b/proxy/protocol/http/http_server.go
index b47dc3a..c7b73e6 100644
--- a/proxy/protocol/http/http_server.go
+++ b/proxy/protocol/http/http_server.go
@@ -18,24 +18,26 @@
package http
import (
+ "context"
"crypto/tls"
"errors"
"fmt"
- "github.com/apache/servicecomb-mesher/proxy/common"
- "github.com/apache/servicecomb-mesher/proxy/config"
- "github.com/apache/servicecomb-mesher/proxy/protocol/dubbo/proxy"
- "github.com/apache/servicecomb-mesher/proxy/resolver"
+ "github.com/apache/servicecomb-mesher/proxy/ingress"
"net"
"net/http"
"strings"
- "context"
+ "github.com/apache/servicecomb-mesher/proxy/common"
+ "github.com/apache/servicecomb-mesher/proxy/config"
"github.com/apache/servicecomb-mesher/proxy/pkg/runtime"
+ "github.com/apache/servicecomb-mesher/proxy/protocol/dubbo/proxy"
+ "github.com/apache/servicecomb-mesher/proxy/resolver"
chassisCom "github.com/go-chassis/go-chassis/core/common"
chassisConfig "github.com/go-chassis/go-chassis/core/config"
"github.com/go-chassis/go-chassis/core/lager"
"github.com/go-chassis/go-chassis/core/server"
chassisTLS "github.com/go-chassis/go-chassis/core/tls"
+ chassisRuntime "github.com/go-chassis/go-chassis/pkg/runtime"
"github.com/go-mesh/openlogging"
)
@@ -75,11 +77,11 @@
return fmt.Errorf("only support ipv4, input is [%s]", hs.opts.Address)
}
- switch runtime.Mode {
- case common.ModeSidecar:
+ switch runtime.Role {
+ case common.RoleSidecar:
err = hs.startSidecar(host, port)
- case common.ModePerHost:
- err = hs.startPerHost()
+ default:
+ err = hs.startCommonProxy()
}
if err != nil {
return err
@@ -139,20 +141,22 @@
return nil
}
-func (hs *httpServer) startPerHost() error {
- sslTag := genTag(common.ComponentName, chassisCom.Provider)
+func (hs *httpServer) startCommonProxy() error {
+ if err := ingress.Init(); err != nil {
+ return err
+ }
mesherTLSConfig, mesherSSLConfig, err := chassisTLS.GetTLSConfigByService(
- common.ComponentName, "", chassisCom.Provider)
+ chassisRuntime.ServiceName, "rest", chassisCom.Provider)
if err != nil {
if !chassisTLS.IsSSLConfigNotExist(err) {
return err
}
} else {
- lager.Logger.Warnf("%s TLS mode, verify peer: %t, cipher plugin: %s.",
- sslTag, mesherSSLConfig.VerifyPeer, mesherSSLConfig.CipherPlugin)
+ lager.Logger.Warnf("TLS mode, verify peer: %t, cipher plugin: %s.",
+ mesherSSLConfig.VerifyPeer, mesherSSLConfig.CipherPlugin)
}
- err = hs.listenAndServe(hs.opts.Address, mesherTLSConfig, http.HandlerFunc(LocalRequestHandler))
+ err = hs.listenAndServe(hs.opts.Address, mesherTLSConfig, http.HandlerFunc(HandleIngressTraffic))
if err != nil {
return err
}
@@ -165,6 +169,7 @@
return err
}
if t != nil {
+ openlogging.Info("run as https")
lnTLS := tls.NewListener(ln, t)
ln = lnTLS
}
@@ -181,7 +186,7 @@
}
func (hs *httpServer) Stop() error {
- //go 1.8+ drain connections before stop server
+ //go 1.8+ drain connections handleIncomingTraffic stop server
if hs.server == nil {
openlogging.Info("http server don't need to be stopped")
return nil
diff --git a/proxy/protocol/http/reverse_proxy.go b/proxy/protocol/http/sidecar.go
similarity index 98%
rename from proxy/protocol/http/reverse_proxy.go
rename to proxy/protocol/http/sidecar.go
index 09d6357..144e852 100755
--- a/proxy/protocol/http/reverse_proxy.go
+++ b/proxy/protocol/http/sidecar.go
@@ -95,7 +95,7 @@
func LocalRequestHandler(w http.ResponseWriter, r *http.Request) {
prepareRequest(r)
inv := consumerPreHandler(r)
- source := stringutil.SplitFirstSep(r.RemoteAddr, ":")
+ remoteIP := stringutil.SplitFirstSep(r.RemoteAddr, ":")
var err error
h := make(map[string]string)
@@ -103,12 +103,12 @@
h[k] = r.Header.Get(k)
}
//Resolve Destination
- port, err := dr.Resolve(source, h, r.URL.String(), &inv.MicroServiceName)
+ destination, port, err := dr.Resolve(remoteIP, r.Host, r.URL.String(), h)
if err != nil {
handleErrorResponse(inv, w, http.StatusBadRequest, err)
return
}
-
+ inv.MicroServiceName = destination
if port != "" {
h[XForwardedPort] = port
}
diff --git a/proxy/resolver/authority/destination.go b/proxy/resolver/authority/destination.go
index b6e2467..577a503 100644
--- a/proxy/resolver/authority/destination.go
+++ b/proxy/resolver/authority/destination.go
@@ -29,16 +29,15 @@
}
//Resolve resolves service name
-func (dr *GRPCDefaultDestinationResolver) Resolve(sourceAddr string, header map[string]string, rawURI string, destinationName *string) (string, error) {
+func (dr *GRPCDefaultDestinationResolver) Resolve(sourceAddr, host, rawURI string, header map[string]string) (string, string, error) {
s := strings.Split(rawURI, ":")
if len(s) != 2 {
err := fmt.Errorf("can not parse [%s]", rawURI)
openlogging.Error(err.Error())
- return "", err
+ return "", "", err
}
- *destinationName = s[0]
- return s[1], nil
+ return s[0], s[1], nil
}
//New return return dr
diff --git a/proxy/resolver/authority/destination_test.go b/proxy/resolver/authority/destination_test.go
index a2a5967..ecc0391 100644
--- a/proxy/resolver/authority/destination_test.go
+++ b/proxy/resolver/authority/destination_test.go
@@ -34,35 +34,32 @@
header := http.Header{}
header.Add("cookie", "user=jason")
header.Add("X-Age", "18")
- mystring := "Server"
- var destinationString = &mystring
- p, err := d.Resolve("abc", map[string]string{}, "127.0.1.1", destinationString)
+ var destinationString = "Server"
+ destinationString, p, err := d.Resolve("abc", "", "127.0.1.1", map[string]string{})
assert.Error(t, err)
assert.Equal(t, "", p)
- p, err = d.Resolve("abc", map[string]string{}, "", destinationString)
+ destinationString, p, err = d.Resolve("abc", "", "", map[string]string{})
assert.Error(t, err)
assert.Equal(t, "", p)
- p, err = d.Resolve("abc", map[string]string{}, "127.0.0.1:80", destinationString)
+ destinationString, p, err = d.Resolve("abc", "", "127.0.0.1:80", map[string]string{})
assert.NoError(t, err)
assert.Equal(t, "80", p)
dr := resolver.GetDestinationResolver("grpc")
- p, err = dr.Resolve("abc", map[string]string{}, "127.0.0.1:80", destinationString)
+ destinationString, p, err = dr.Resolve("abc", "", "127.0.0.1:80", map[string]string{})
assert.NoError(t, err)
assert.Equal(t, "80", p)
-
+ t.Log(destinationString)
}
func BenchmarkDefaultDestinationResolver_Resolve(b *testing.B) {
lager.Initialize("", "DEBUG", "",
"size", true, 1, 10, 7)
d := &authority.GRPCDefaultDestinationResolver{}
- mystring := "Server"
- var destinationString = &mystring
for i := 0; i < b.N; i++ {
- d.Resolve("abc", map[string]string{}, "127.0.0.1:80", destinationString)
+ d.Resolve("abc", "", "127.0.0.1:80", map[string]string{})
}
}
diff --git a/proxy/resolver/destination.go b/proxy/resolver/destination.go
index 0d62faf..1432186 100644
--- a/proxy/resolver/destination.go
+++ b/proxy/resolver/destination.go
@@ -43,34 +43,34 @@
//DestinationResolver is a interface with Resolve method
type DestinationResolver interface {
- Resolve(sourceAddr string, header map[string]string, rawURI string, destinationName *string) (string, error)
+ Resolve(remoteIP, host, rawURI string, header map[string]string) (string, string, error)
}
//DefaultDestinationResolver is a struct
+//mesher as sidecar must use DefaultDestinationResolver
type DefaultDestinationResolver struct {
}
//Resolve resolves service's endpoint
//service may have multiple port for same protocol
-func (dr *DefaultDestinationResolver) Resolve(sourceAddr string, header map[string]string, rawURI string, destinationName *string) (string, error) {
+func (dr *DefaultDestinationResolver) Resolve(remoteIP, host, rawURI string, header map[string]string) (string, string, error) {
u, err := url.Parse(rawURI)
if err != nil {
openlogging.Error("Can not parse url: " + err.Error())
- return "", err
+ return "", "", err
}
if u.Host == "" {
- return "", errors.New(`Invalid uri, please check:
+ return "", "", errors.New(`Invalid uri, please check:
1, For provider, mesher listens on external ip
2, Set http_proxy as mesher address, before sending request`)
}
if u.Host == SelfEndpoint {
- return "", errors.New(`uri format must be: http://serviceName/api`)
+ return "", "", errors.New(`uri format must be: http://serviceName/api`)
}
- *destinationName = u.Hostname()
- return u.Port(), nil
+ return u.Hostname(), u.Port(), nil
}
//New function returns new DefaultDestinationResolver struct object
diff --git a/proxy/resolver/destination_test.go b/proxy/resolver/destination_test.go
index b95a0e0..ae647d7 100644
--- a/proxy/resolver/destination_test.go
+++ b/proxy/resolver/destination_test.go
@@ -61,26 +61,26 @@
header := http.Header{}
header.Add("cookie", "user=jason")
header.Add("X-Age", "18")
- mystring := "Server"
- var destinationString = &mystring
- p, err := d.Resolve("abc", map[string]string{}, "127.0.1.1", destinationString)
+ destinationString := "Server"
+ destinationString, p, err := d.Resolve("127.0.1.1", "abc", "", map[string]string{})
assert.Error(t, err)
assert.Equal(t, "", p)
- p, err = d.Resolve("abc", map[string]string{}, "", destinationString)
+ destinationString, p, err = d.Resolve("abc", "", "", map[string]string{})
assert.Error(t, err)
assert.Equal(t, "", p)
- p, err = d.Resolve("abc", map[string]string{}, "http://127.0.0.1:80/test", destinationString)
+ destinationString, p, err = d.Resolve("abc", "", "http://127.0.0.1:80/test", map[string]string{})
assert.NoError(t, err)
assert.Equal(t, "80", p)
- p, err = d.Resolve("abc", map[string]string{}, "Server:80/test", destinationString)
+ destinationString, p, err = d.Resolve("abc", "", "Server:80/test", map[string]string{})
assert.Error(t, err)
- p, err = d.Resolve("abc", map[string]string{}, "127.0.0.1:80", destinationString)
+ destinationString, p, err = d.Resolve("abc", "", "127.0.0.1:80", map[string]string{})
assert.Error(t, err)
assert.Equal(t, "", p)
+ t.Log(destinationString)
}
func TestGetDestinationResolver(t *testing.T) {
@@ -97,9 +97,7 @@
lager.Initialize("", "DEBUG", "",
"size", true, 1, 10, 7)
d := &DefaultDestinationResolver{}
- mystring := "Server"
- var destinationString = &mystring
for i := 0; i < b.N; i++ {
- d.Resolve("abc", map[string]string{}, "http://127.0.0.1:80/test", destinationString)
+ d.Resolve("abc", "", "http://127.0.0.1:80/test", map[string]string{})
}
}
diff --git a/proxy/util/compara_test.go b/proxy/util/compara_test.go
deleted file mode 100644
index ebaf1a9..0000000
--- a/proxy/util/compara_test.go
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * 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 util_test
-
-import (
- "github.com/apache/servicecomb-mesher/proxy/config"
- "github.com/apache/servicecomb-mesher/proxy/util"
- "github.com/go-chassis/go-chassis/core/invocation"
- "github.com/go-chassis/go-chassis/pkg/util/tags"
- "github.com/stretchr/testify/assert"
- "testing"
-)
-
-func TestEqualPolicy(t *testing.T) {
-
- i := &invocation.Invocation{
- MicroServiceName: "ShoppingCart",
- }
-
- i.RouteTags = utiltags.NewDefaultTag("0.1", "default")
- tags := make(map[string]string)
- tags["app"] = "default"
- tags["version"] = "0.0.1"
- p := &config.Policy{
- Destination: "ShoppingCart1",
- Tags: tags,
- LoadBalancing: nil,
- }
- value := util.EqualPolicy(i, p)
- assert.Equal(t, value, false)
-
- i = &invocation.Invocation{
- MicroServiceName: "ShoppingCart",
- }
-
- i.RouteTags = utiltags.NewDefaultTag("0.1", "default1")
- tags = make(map[string]string)
- tags["app"] = "default"
- tags["version"] = "0.0.1"
- p = &config.Policy{
- Destination: "ShoppingCart",
- Tags: tags,
- LoadBalancing: nil,
- }
- value = util.EqualPolicy(i, p)
- assert.Equal(t, value, false)
- i = &invocation.Invocation{
- MicroServiceName: "ShoppingCart",
- }
-
- i.RouteTags = utiltags.NewDefaultTag("0.1", "default")
- tags = make(map[string]string)
- tags["app"] = "default"
-
- tags["version"] = "0.0.1"
- p = &config.Policy{
- Destination: "ShoppingCart",
- Tags: tags,
- LoadBalancing: nil,
- }
- value = util.EqualPolicy(i, p)
- assert.Equal(t, value, false)
-
- i = &invocation.Invocation{
- MicroServiceName: "ShoppingCart",
- }
-
- i.RouteTags = utiltags.NewDefaultTag("0.1", "default")
- tags = make(map[string]string)
- tags["app1"] = "default"
- tags["version1"] = "0.1"
- p = &config.Policy{
- Destination: "ShoppingCart",
- Tags: tags,
- LoadBalancing: nil,
- }
- value = util.EqualPolicy(i, p)
- assert.Equal(t, value, false)
-
- i = &invocation.Invocation{
- MicroServiceName: "ShoppingCart",
- }
- inv := make(map[string]interface{})
- inv["app1"] = 1
- i.Metadata = inv
- i.RouteTags = utiltags.NewDefaultTag("0.1", "default")
- tags = make(map[string]string)
- tags["app1"] = "default"
- tags["version1"] = "0.1"
- p = &config.Policy{
- Destination: "ShoppingCart",
- Tags: tags,
- LoadBalancing: nil,
- }
- value = util.EqualPolicy(i, p)
- assert.Equal(t, value, false)
-
- i = &invocation.Invocation{
- MicroServiceName: "ShoppingCart",
- }
- inv = make(map[string]interface{})
- inv["app"] = "default"
- i.Metadata = inv
- i.RouteTags = utiltags.NewDefaultTag("0.1", "default")
- tags = make(map[string]string)
- tags["app"] = "default1"
- tags["version"] = "0.1"
- p = &config.Policy{
- Destination: "ShoppingCart",
- Tags: tags,
- LoadBalancing: nil,
- }
- value = util.EqualPolicy(i, p)
- assert.Equal(t, value, false)
-
- i = &invocation.Invocation{
- MicroServiceName: "ShoppingCart",
- }
-
- i.RouteTags = utiltags.NewDefaultTag("0.1", "default")
- tags = make(map[string]string)
- tags["app"] = "default"
- tags["version"] = "0.1"
- p = &config.Policy{
- Destination: "ShoppingCart",
- Tags: tags,
- LoadBalancing: nil,
- }
- value = util.EqualPolicy(i, p)
- assert.Equal(t, value, true)
-
-}
diff --git a/proxy/util/compare.go b/proxy/util/compare.go
deleted file mode 100644
index 7b72659..0000000
--- a/proxy/util/compare.go
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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 util
-
-import (
- "github.com/apache/servicecomb-mesher/proxy/common"
- "github.com/apache/servicecomb-mesher/proxy/config"
- "github.com/go-chassis/go-chassis/core/invocation"
-)
-
-//EqualPolicy is a function
-func EqualPolicy(inv *invocation.Invocation, p *config.Policy) bool {
- if inv.MicroServiceName != p.Destination {
- return false
- }
- for k, v := range p.Tags {
- if k == common.BuildInTagApp {
- if v == "" {
- v = common.DefaultApp
- }
- if v != inv.RouteTags.AppID() {
- return false
- }
- continue
- }
- if k == common.BuildInTagVersion {
- if v == "" {
- v = common.DefaultVersion
- }
- if v != inv.RouteTags.Version() {
- return false
- }
- continue
- }
- t, ok := inv.Metadata[k]
- if !ok {
- return false
- }
- if _, ok := t.(string); !ok {
- return false
- }
- }
- for k, v := range inv.Metadata {
- if v != p.Tags[k] {
- return false
- }
- }
- return true
-
-}