diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml index 7eb0dea0f..2327a6e94 100644 --- a/.github/workflows/github-actions.yml +++ b/.github/workflows/github-actions.yml @@ -93,8 +93,11 @@ jobs: - name: Go Test run: | chmod u+x before_ut.sh && ./before_ut.sh - go mod vendor && go test ./... -coverprofile=coverage.txt -covermode=atomic -# chmod +x integrate_test.sh && ./integrate_test.sh + go mod vendor && go test ./pkg/... -coverprofile=coverage.txt -covermode=atomic + # integration test + - name: Integration Test + run: | + chmod +x start_integrate_test.sh && chmod +x integrate_test.sh && ./start_integrate_test.sh - name: Coverage run: bash <(curl -s https://codecov.io/bash) diff --git a/.travis.yml b/.travis.yml index 118731ac1..74a6d487d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,7 +33,7 @@ script: # unit-test - echo 'start unit-test' - chmod u+x before_ut.sh && ./before_ut.sh - - go mod vendor && go test ./... -coverprofile=coverage.txt -covermode=atomic + - go mod vendor && go test ./pkg/... -coverprofile=coverage.txt -covermode=atomic after_success: - bash <(curl -s https://codecov.io/bash) diff --git a/build/Makefile b/build/Makefile new file mode 100644 index 000000000..c27129cb7 --- /dev/null +++ b/build/Makefile @@ -0,0 +1,152 @@ +# +# Licensed to 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. Apache Software Foundation (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. +# + +PROJECT_NAME = $(shell basename "$(PWD)") +PID = /tmp/.$(PROJECT_NAME).pid +PROJECT_DIR=$(shell pwd) +BASE_DIR := $(PROJECT_DIR)/dist +PIXIU_DIR := $(PIXIU_DIR) +PIXIU_PID = /tmp/.pixiu.pid + +SOURCES = $(wildcard $(PROJECT_DIR)/server/app/*.go) +pixiuSources = $(wildcard $(PIXIU_DIR)/cmd/pixiu/*.go) + +export GO111MODULE ?= on +export GOPROXY ?= https://goproxy.io,direct +export GOSUMDB ?= sum.golang.org +export GOARCH ?= amd64 + +export DOCKER_HOST_IP = $(shell ifconfig en0 | grep inet | grep -v inet6 | awk '{print $$2}') + +OS := $(shell uname) +ifeq ($(OS), Linux) + export GOOS ?= linux +else ifeq ($(OS), Darwin) + export GOOS ?= darwin +else + export GOOS ?= windows +endif + +ifeq ($(GOOS), windows) + export EXT_NAME ?= .exe +else + export EXT_NAME ?= +endif + +CGO ?= 0 +ifeq ($(DEBUG), true) + BUILD_TYPE := debug + GCFLAGS := -gcflags="all=-N -l" + LCFLAGS := +else + BUILD_TYPE := release + LDFLAGS := "-s -w" +endif + +OUT_DIR := $(BASE_DIR)/$(GOOS)_$(GOARCH)/$(rtfg8u7) +LOG_FILE := $(OUT_DIR)/$(PROJECT_NAME).log +API_CONFIG_PATH := $(OUT_DIR)/pixiuconf/api_config.yaml +CONFIG_PATH := $(OUT_DIR)/pixiuconf/conf.yaml + +export APP_LOG_CONF_FILE ?= $(OUT_DIR)/conf/log.yml + +.PHONY: all +all: help +help: $(realpath $(firstword $(MAKEFILE_LIST))) + @echo + @echo " Choose a command run in "$(PROJECT_NAME)":" + @echo + @sed -n 's/^##//p' $< | column -t -s ':' | sed -e 's/^/ /' + @echo + +## build: Build application's binaries +.PHONY: build +build: $(OUT_DIR)/$(PROJECT_NAME)$(EXT_NAME) config + +.PHONY: $(OUT_DIR)/$(PROJECT_NAME)$(EXT_NAME) +$(OUT_DIR)/$(PROJECT_NAME)$(EXT_NAME): + $(info > Buiding application binary: $(OUT_DIR)/$(PROJECT_NAME)$(EXT_NAME)) + @CGO_ENABLED=$(CGO) GOOS=$(GOOS) GOARCH=$(GOARCH) go build $(GCFLAGS) -ldflags=$(LDFLAGS) -i -o $(OUT_DIR)/server/$(PROJECT_NAME)$(EXT_NAME) $(SOURCES) + + +## config: Setup config files +.PHONY: config +config: + $(info > Setting up config files) + @mkdir -p $(OUT_DIR)/server + @mkdir -p $(OUT_DIR)/pixiuconf + @-test -f $(PROJECT_DIR)/server/profiles/dev/log.yml && cat $(PROJECT_DIR)/server/profiles/dev/log.yml | sed "s#\$$HOST_IP#$(DOCKER_HOST_IP)#g" > $(OUT_DIR)/server/log.yml && echo " > $(OUT_DIR)/conf/log.yml" + @-test -f $(PROJECT_DIR)/server/profiles/dev/server.yml && cat $(PROJECT_DIR)/server/profiles/dev/server.yml | sed "s#\$$HOST_IP#$(DOCKER_HOST_IP)#g" > $(OUT_DIR)/server/server.yml && echo " > $(OUT_DIR)/conf/server.yml" + @-test -f $(PROJECT_DIR)/pixiu/api_config.yaml && cat $(PROJECT_DIR)/pixiu/api_config.yaml | sed "s#\$$HOST_IP#$(DOCKER_HOST_IP)#g" > $(OUT_DIR)/pixiuconf/api_config.yaml && echo " > $(OUT_DIR)/pixiuconf/api_config.yaml" + @-test -f $(PROJECT_DIR)/pixiu/conf.yaml && cat $(PROJECT_DIR)/pixiu/conf.yaml | sed "s#\$$HOST_IP#$(DOCKER_HOST_IP)#g" > $(OUT_DIR)/pixiuconf/conf.yaml && echo " > $(OUT_DIR)/pixiuconf/conf.yaml" + +## docker-up: Shutdown dependency services on docker +.PHONY: docker-up +docker-up: + $(info > Starting dependency services with $(PROJECT_DIR)/docker/docker-compose.yml) + @docker-compose -f $(PROJECT_DIR)/docker/docker-compose.yml up -d + +## docker-down: Shutdown dependency services on docker +.PHONY: docker-down +docker-down: + $(info > Stopping dependency services with $(PROJECT_DIR)/docker/docker-compose.yml) + @docker-compose -f $(PROJECT_DIR)/docker/docker-compose.yml down + +## clean: Clean up the output and the binary of the application +.PHONY: clean +clean: stop + $(info > Cleanning up $(OUT_DIR)) + @-rm -rf $(OUT_DIR) + @-cat $(PID) | awk '{print $1}' | xargs kill -9 + @-cat $(PIXIU_PID) | awk '{print $1}' | xargs kill -9 + +## start: Start the application (for server) +.PHONY: start +start: export CONF_PROVIDER_FILE_PATH ?= $(OUT_DIR)/server/server.yml +start: build + $(info > Starting application $(PROJECT_NAME), output is redirected to $(LOG_FILE)) + @-$(OUT_DIR)/server/$(PROJECT_NAME)$(EXT_NAME) > $(LOG_FILE) 2>&1 & echo $$! > $(PID) + @cat $(PID) | sed "/^/s/^/ \> PID: /" + +## run: Run the application (for client) +.PHONY: run +run: buildPixiu + $(info > Running application PIXIU, output is redirected to $(LOG_FILE)) + +## buildPixiu: start pixiu +.PHONY: buildPixiu +buildPixiu: + @CGO_ENABLED=$(CGO) GOOS=$(GOOS) GOARCH=$(GOARCH) go build $(GCFLAGS) -ldflags=$(LDFLAGS) -i -o $(OUT_DIR)/pixiu$(EXT_NAME) $(pixiuSources) + @-$(OUT_DIR)/pixiu$(EXT_NAME) -a $(API_CONFIG_PATH) -c $(CONFIG_PATH) & echo $$! > $(PIXIU_PID) + @cat $(PIXIU_PID) | sed "/^/s/^/ \> PIXIU_PID: /" +## stop: Stop running the application (for server) +.PHONY: stop +stop: + $(info > Stopping the application $(PROJECT_NAME)) + @cat $(PID) | sed "/^/s/^/ \> Killing PID: /" + @-kill `cat $(PID)` 2>/dev/null || true + +## integration: Run integration test for this application +.PHONY: integration +integration: export CONF_CONSUMER_FILE_PATH ?= $(OUT_DIR)/conf/client.yml +integration: export CONF_ROUTER_FILE_PATH ?= $(OUT_DIR)/conf/router_config.yml +integration: + $(info > Running integration test for application $(PROJECT_NAME)) + @go clean -testcache + @go test -tags integration -v $(PROJECT_DIR)/test/... diff --git a/cmd/pixiu/pixiu.go b/cmd/pixiu/pixiu.go index d44311b88..df2e99a97 100644 --- a/cmd/pixiu/pixiu.go +++ b/cmd/pixiu/pixiu.go @@ -30,15 +30,6 @@ import ( "github.com/urfave/cli" ) -import ( - _ "github.com/apache/dubbo-go-pixiu/pkg/filter/accesslog" - _ "github.com/apache/dubbo-go-pixiu/pkg/filter/logger" - _ "github.com/apache/dubbo-go-pixiu/pkg/filter/recovery" - _ "github.com/apache/dubbo-go-pixiu/pkg/filter/remote" - _ "github.com/apache/dubbo-go-pixiu/pkg/filter/response" - _ "github.com/apache/dubbo-go-pixiu/pkg/filter/timeout" -) - // Version pixiu version var Version = "0.3.0" diff --git a/integrate_test.sh b/integrate_test.sh new file mode 100644 index 000000000..e7bb01773 --- /dev/null +++ b/integrate_test.sh @@ -0,0 +1,39 @@ +# +# 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. + +if [ -z "$1" ]; then + echo 'Provide test directory please, like : ./integrate_test.sh $(pwd)/samples/simple/server .' + exit +fi + +P_DIR=$(pwd)/$1 +PIXIU_DIR=$(pwd) + +make PROJECT_DIR=$P_DIR PIXIU_DIR=$PIXIU_DIR PROJECT_NAME=$(basename $P_DIR) BASE_DIR=$P_DIR/dist -f build/Makefile docker-up + +# start server +make PROJECT_DIR=$P_DIR PIXIU_DIR=$PIXIU_DIR PROJECT_NAME=$(basename $P_DIR) BASE_DIR=$P_DIR/dist -f build/Makefile start +# start pixiu +make PROJECT_DIR=$P_DIR PIXIU_DIR=$PIXIU_DIR PROJECT_NAME=$(basename $P_DIR) BASE_DIR=$P_DIR/dist -f build/Makefile buildPixiu +# start integration +make PROJECT_DIR=$P_DIR PIXIU_DIR=$PIXIU_DIR PROJECT_NAME=$(basename $P_DIR) BASE_DIR=$P_DIR/dist -f build/Makefile integration +result=$? +# stop server +make PROJECT_DIR=$P_DIR PIXIU_DIR=$PIXIU_DIR PROJECT_NAME=$(basename $P_DIR) BASE_DIR=$P_DIR/dist -f build/Makefile clean + +make PROJECT_DIR=$P_DIR PIXIU_DIR=$PIXIU_DIR PROJECT_NAME=$(basename $P_DIR) BASE_DIR=$P_DIR/dist -f build/Makefile docker-down + +exit $((result)) diff --git a/pkg/client/dubbo/dubbo.go b/pkg/client/dubbo/dubbo.go index 9e5454e36..510c3d6d3 100644 --- a/pkg/client/dubbo/dubbo.go +++ b/pkg/client/dubbo/dubbo.go @@ -260,7 +260,9 @@ func (dc *Client) create(key string, irequest fc.IntegrationRequest) *dg.Generic dc.lock.Lock() defer dc.lock.Unlock() referenceConfig.GenericLoad(key) - time.Sleep(200 * time.Millisecond) // sleep to wait invoker create + //TODO: fix it later + // sleep to wait invoker create + time.Sleep(500 * time.Millisecond) clientService := referenceConfig.GetRPCService().(*dg.GenericService) dc.GenericServicePool[key] = clientService diff --git a/pkg/config/api_config.go b/pkg/config/api_config.go index a23285f65..4e62f60a8 100644 --- a/pkg/config/api_config.go +++ b/pkg/config/api_config.go @@ -27,6 +27,7 @@ import ( import ( fc "github.com/dubbogo/dubbo-go-pixiu-filter/pkg/api/config" + fr "github.com/dubbogo/dubbo-go-pixiu-filter/pkg/api/config/ratelimit" etcdv3 "github.com/dubbogo/gost/database/kv/etcd/v3" perrors "github.com/pkg/errors" "go.etcd.io/etcd/clientv3" @@ -47,6 +48,12 @@ var ( lock sync.RWMutex ) +var ( + BASE_INFO_NAME = "name" + BASE_INFO_DESC = "description" + BASE_INFO_PFP = "pluginFilePath" +) + // APIConfigResourceListener defines api resource and method config listener interface type APIConfigResourceListener interface { // ResourceChange handle modify resource event @@ -61,6 +68,12 @@ type APIConfigResourceListener interface { MethodAdd(res fc.Resource, method fc.Method) bool // MethodDelete handle delete method event MethodDelete(res fc.Resource, method fc.Method) bool + + PluginPathChange(filePath string) + + PluginGroupChange(group []fc.PluginsGroup) + + RateLimitChange(*fr.Config) } // LoadAPIConfigFromFile load the api config from file @@ -72,7 +85,7 @@ func LoadAPIConfigFromFile(path string) (*fc.APIConfig, error) { apiConf := &fc.APIConfig{} err := yaml.UnmarshalYMLConfig(path, apiConf) if err != nil { - return nil, perrors.Errorf("unmarshalYmlConfig error %v", perrors.WithStack(err)) + return nil, perrors.Errorf("unmarshalYmlConfig error %s", perrors.WithStack(err)) } apiConfig = apiConf return apiConf, nil @@ -86,13 +99,13 @@ func LoadAPIConfig(metaConfig *model.APIMetaConfig) (*fc.APIConfig, error) { etcdv3.WithEndpoints(strings.Split(metaConfig.Address, ",")...), ) if err != nil { - return nil, perrors.Errorf("Init etcd client fail error %v", err) + return nil, perrors.Errorf("Init etcd client fail error %s", err) } client = tmpClient kList, vList, err := client.GetChildren(metaConfig.APIConfigPath) if err != nil { - return nil, perrors.Errorf("Get remote config fail error %v", err) + return nil, perrors.Errorf("Get remote config fail error %s", err) } if err = initAPIConfigFromKVList(kList, vList); err != nil { return nil, err @@ -105,11 +118,21 @@ func LoadAPIConfig(metaConfig *model.APIMetaConfig) (*fc.APIConfig, error) { func initAPIConfigFromKVList(kList, vList []string) error { var skList, svList, mkList, mvList []string + var baseInfo string + var pluginGroup []string + var rateLimit string for i, k := range kList { v := vList[i] + //handle base info + re := getCheckBaseInfoRegexp() + if m := re.Match([]byte(k)); m { + baseInfo = v + continue + } + // handle resource - re := getCheckResourceRegexp() + re = getCheckResourceRegexp() if m := re.Match([]byte(k)); m { skList = append(skList, k) svList = append(svList, v) @@ -122,18 +145,44 @@ func initAPIConfigFromKVList(kList, vList []string) error { mvList = append(mvList, v) continue } + + //handle plugin group + re = getCheckPluginsGroupRegexp() + if m := re.Match([]byte(k)); m { + pluginGroup = append(pluginGroup, v) + continue + } + + //handle rate limit config + re = getCheckRatelimitRegexp() + if m := re.Match([]byte(k)); m { + rateLimit = v + continue + } } lock.Lock() defer lock.Unlock() tmpApiConf := &fc.APIConfig{} + if err := initBaseInfoFromString(tmpApiConf, baseInfo); err != nil { + logger.Errorf("initBaseInfoFromString error %s", err) + return err + } if err := initAPIConfigServiceFromKvList(tmpApiConf, skList, svList); err != nil { - logger.Error("initAPIConfigServiceFromKvList error %v", err.Error()) + logger.Errorf("initAPIConfigServiceFromKvList error %s", err) return err } if err := initAPIConfigMethodFromKvList(tmpApiConf, mkList, mvList); err != nil { - logger.Error("initAPIConfigMethodFromKvList error %v", err.Error()) + logger.Errorf("initAPIConfigMethodFromKvList error %s", err) + return err + } + if err := initAPIConfigPluginsFromStringList(tmpApiConf, pluginGroup); err != nil { + logger.Errorf("initAPIConfigPluginsFromStringList error %s", err) + return err + } + if err := initAPIConfigRatelimitFromString(tmpApiConf, rateLimit); err != nil { + logger.Errorf("initAPIConfigRatelimitFromString error %s", err) return err } @@ -141,13 +190,55 @@ func initAPIConfigFromKVList(kList, vList []string) error { return nil } +func initBaseInfoFromString(conf *fc.APIConfig, str string) error { + properties := make(map[string]string, 8) + if err := yaml.UnmarshalYML([]byte(str), properties); err != nil { + logger.Errorf("unmarshalYmlConfig error %s", err) + return err + } + if v, ok := properties[BASE_INFO_NAME]; ok { + conf.Name = v + } + if v, ok := properties[BASE_INFO_DESC]; ok { + conf.Description = v + } + if v, ok := properties[BASE_INFO_PFP]; ok { + conf.PluginFilePath = v + } + return nil +} + +func initAPIConfigRatelimitFromString(conf *fc.APIConfig, str string) error { + c := fr.Config{} + if err := yaml.UnmarshalYML([]byte(str), &c); err != nil { + logger.Errorf("unmarshalYmlConfig error %s", err) + return err + } + conf.RateLimit = c + return nil +} + +func initAPIConfigPluginsFromStringList(conf *fc.APIConfig, plugins []string) error { + var groups []fc.PluginsGroup + for _, v := range plugins { + g := fc.PluginsGroup{} + if err := yaml.UnmarshalYML([]byte(v), &g); err != nil { + logger.Errorf("unmarshalYmlConfig error %s", err) + return err + } + groups = append(groups, g) + } + conf.PluginsGroup = groups + return nil +} + func initAPIConfigMethodFromKvList(config *fc.APIConfig, kList, vList []string) error { for i := range kList { v := vList[i] method := &fc.Method{} err := yaml.UnmarshalYML([]byte(v), method) if err != nil { - logger.Error("unmarshalYmlConfig error %v", err.Error()) + logger.Errorf("unmarshalYmlConfig error %s", err) return err } @@ -188,7 +279,7 @@ func initAPIConfigServiceFromKvList(config *fc.APIConfig, kList, vList []string) resource := &fc.Resource{} err := yaml.UnmarshalYML([]byte(v), resource) if err != nil { - logger.Error("unmarshalYmlConfig error %v", err.Error()) + logger.Errorf("unmarshalYmlConfig error %s", err) return err } @@ -219,7 +310,7 @@ func listenResourceAndMethodEvent(key string) bool { for { wc, err := client.WatchWithOption(key, clientv3.WithPrefix()) if err != nil { - logger.Warnf("Watch api config {key:%s} = error{%v}", key, err) + logger.Warnf("Watch api config {key:%s} = error{%s}", key, err) return false } @@ -275,7 +366,7 @@ func handleDeleteEvent(key, val []byte) { resourceIdStr := pathArray[len(pathArray)-1] ID, err := strconv.Atoi(resourceIdStr) if err != nil { - logger.Error("handleDeleteEvent ID is not int error %v", err) + logger.Errorf("handleDeleteEvent ID is not int error %s", err) return } deleteApiConfigResource(ID) @@ -292,18 +383,24 @@ func handleDeleteEvent(key, val []byte) { resourceIdStr := pathArray[len(pathArray)-3] resourceId, err := strconv.Atoi(resourceIdStr) if err != nil { - logger.Error("handleDeleteEvent ID is not int error %v", err) + logger.Errorf("handleDeleteEvent ID is not int error %s", err) return } methodIdStr := pathArray[len(pathArray)-1] methodId, err := strconv.Atoi(methodIdStr) if err != nil { - logger.Error("handleDeleteEvent ID is not int error %v", err) + logger.Errorf("handleDeleteEvent ID is not int error %s", err) return } deleteApiConfigMethod(resourceId, methodId) } + + re = getCheckRatelimitRegexp() + if m := re.Match(key); m { + empty := &fr.Config{} + listener.RateLimitChange(empty) + } } func handlePutEvent(key, val []byte) { @@ -315,7 +412,7 @@ func handlePutEvent(key, val []byte) { res := &fc.Resource{} err := yaml.UnmarshalYML(val, res) if err != nil { - logger.Error("handlePutEvent UnmarshalYML error %v", err) + logger.Errorf("handlePutEvent UnmarshalYML error %s", err) return } mergeApiConfigResource(*res) @@ -327,11 +424,32 @@ func handlePutEvent(key, val []byte) { res := &fc.Method{} err := yaml.UnmarshalYML(val, res) if err != nil { - logger.Error("handlePutEvent UnmarshalYML error %v", err) + logger.Errorf("handlePutEvent UnmarshalYML error %s", err) return } mergeApiConfigMethod(res.ResourcePath, *res) } + + //handle base info + re = getCheckBaseInfoRegexp() + if m := re.Match(key); m { + mergeBaseInfo(val) + return + } + + //handle plugins group + re = getCheckPluginsGroupRegexp() + if m := re.Match(key); m { + mergePluginGroup(val) + return + } + + //handle ratelimit + re = getCheckRatelimitRegexp() + if m := re.Match(key); m { + mergeRatelimit(val) + return + } } func deleteApiConfigResource(resourceId int) { @@ -361,6 +479,36 @@ func mergeApiConfigResource(val fc.Resource) { listener.ResourceAdd(val) } +func mergeRatelimit(val []byte) { + c := &fr.Config{} + if err := yaml.UnmarshalYML(val, c); err != nil { + logger.Errorf("unmarshalYmlConfig error %s", err) + return + } + apiConfig.RateLimit = *c + listener.RateLimitChange(c) +} + +func mergePluginGroup(val []byte) { + g := &fc.PluginsGroup{} + if err := yaml.UnmarshalYML(val, g); err != nil { + logger.Errorf("unmarshalYmlConfig error %s", err) + return + } + for i, v := range apiConfig.PluginsGroup { + if v.GroupName == g.GroupName { + apiConfig.PluginsGroup[i] = *g + } + } + listener.PluginGroupChange(apiConfig.PluginsGroup) +} + +func mergeBaseInfo(val []byte) { + _ = initBaseInfoFromString(apiConfig, string(val)) + + listener.PluginPathChange(apiConfig.PluginFilePath) +} + func deleteApiConfigMethod(resourceId, methodId int) { for _, resource := range apiConfig.Resources { if resource.ID != resourceId { @@ -401,12 +549,24 @@ func mergeApiConfigMethod(path string, val fc.Method) { } } +func getCheckBaseInfoRegexp() *regexp.Regexp { + return regexp.MustCompile(".+/base$") +} + func getCheckResourceRegexp() *regexp.Regexp { return regexp.MustCompile(".+/resources/[^/]+/?$") } func getExtractMethodRegexp() *regexp.Regexp { - return regexp.MustCompile("resources/([^/]+)/method/[^/]+/?$") + return regexp.MustCompile(".+/resources/([^/]+)/method/[^/]+/?$") +} + +func getCheckPluginsGroupRegexp() *regexp.Regexp { + return regexp.MustCompile(".+/filter/pluginGroup/[^/]+/?$") +} + +func getCheckRatelimitRegexp() *regexp.Regexp { + return regexp.MustCompile(".+/filter/ratelimit/[^/]+/?$") } // RegisterConfigListener register APIConfigListener diff --git a/pkg/filter/accesslog/access_log.go b/pkg/filter/accesslog/access_log.go index 6a1b40ea9..11a13fbd3 100644 --- a/pkg/filter/accesslog/access_log.go +++ b/pkg/filter/accesslog/access_log.go @@ -40,7 +40,7 @@ import ( var accessLogWriter = &model.AccessLogWriter{AccessLogDataChan: make(chan model.AccessLogData, constant.LogDataBuffer)} -func init() { +func Init() { extension.SetFilterFunc(constant.AccessLogFilter, accessLog()) accessLogWriter.Write() } diff --git a/pkg/filter/plugins/plugins.go b/pkg/filter/plugins/plugins.go index 3489d5869..f3bac9c41 100644 --- a/pkg/filter/plugins/plugins.go +++ b/pkg/filter/plugins/plugins.go @@ -38,6 +38,7 @@ var ( // url path -> filter chain filterChainCache = make(map[string]FilterChain) groupCache = make(map[string]map[string]WithFunc) + localFilePath = "" errEmptyConfig = errors.New("Empty plugin config") ) @@ -60,24 +61,33 @@ type WithFunc struct { fn context.FilterFunc } +func OnFilePathChange(filePath string) { + if len(filePath) == 0 { + return + } + localFilePath = filePath +} + // OnResourceUpdate update plugins cache map when api-resource update func OnResourceUpdate(resource *config.Resource) { InitFilterChainForResource(resource, "", nil) } // OnGroupUpdate update group cache -func OnGroupUpdate(groups []config.PluginsGroup, filePath string) { - InitPluginsGroup(groups, filePath) +func OnGroupUpdate(groups []config.PluginsGroup) { + InitPluginsGroup(groups, "") } // InitPluginsGroup prase api_config.yaml(pluginsGroup) to map[string][]PluginsWithFunc func InitPluginsGroup(groups []config.PluginsGroup, filePath string) { - if "" == filePath || len(groups) == 0 { + OnFilePathChange(filePath) + + if "" == localFilePath || len(groups) == 0 { return } // load file.so - pls, err := plugin.Open(filePath) + pls, err := plugin.Open(localFilePath) if nil != err { panic(err) } diff --git a/pkg/filter/ratelimit/rate_limit.go b/pkg/filter/ratelimit/rate_limit.go index 4bbf8cdba..c1f519670 100644 --- a/pkg/filter/ratelimit/rate_limit.go +++ b/pkg/filter/ratelimit/rate_limit.go @@ -42,7 +42,7 @@ import ( // Init cache the filter func & init sentinel func Init(config *ratelimit.Config) { if err := rateLimitInit(config); err != nil { - logger.Errorf("rate limit init fail: %v", err) + logger.Errorf("rate limit init fail: %s", err) //if sentinel init fail, just return a empty filter func to avoid error. extension.SetFilterFunc(constant.RateLimitFilter, func(context fc.Context) {}) diff --git a/pkg/initialize/init.go b/pkg/initialize/init.go index ca90e3b84..9aa7a25ea 100644 --- a/pkg/initialize/init.go +++ b/pkg/initialize/init.go @@ -18,6 +18,7 @@ package initialize import ( + "github.com/apache/dubbo-go-pixiu/pkg/filter/accesslog" "github.com/apache/dubbo-go-pixiu/pkg/filter/api" "github.com/apache/dubbo-go-pixiu/pkg/filter/authority" "github.com/apache/dubbo-go-pixiu/pkg/filter/logger" @@ -41,6 +42,7 @@ func Run(config config.APIConfig) { } func filterInit(config *config.APIConfig) { + accesslog.Init() api.Init() authority.Init() logger.Init() diff --git a/pkg/service/api/discovery_service.go b/pkg/service/api/discovery_service.go index 0042b6a23..ce7a79f6c 100644 --- a/pkg/service/api/discovery_service.go +++ b/pkg/service/api/discovery_service.go @@ -27,12 +27,15 @@ import ( "github.com/apache/dubbo-go-pixiu/pkg/common/constant" "github.com/apache/dubbo-go-pixiu/pkg/common/extension" pc "github.com/apache/dubbo-go-pixiu/pkg/config" + "github.com/apache/dubbo-go-pixiu/pkg/filter/plugins" + "github.com/apache/dubbo-go-pixiu/pkg/filter/ratelimit" "github.com/apache/dubbo-go-pixiu/pkg/router" "github.com/apache/dubbo-go-pixiu/pkg/service" ) import ( "github.com/dubbogo/dubbo-go-pixiu-filter/pkg/api/config" + ratelimitConf "github.com/dubbogo/dubbo-go-pixiu-filter/pkg/api/config/ratelimit" fr "github.com/dubbogo/dubbo-go-pixiu-filter/pkg/router" ) @@ -54,13 +57,13 @@ func NewLocalMemoryAPIDiscoveryService() *LocalMemoryAPIDiscoveryService { } // AddAPI adds a method to the router tree -func (ads *LocalMemoryAPIDiscoveryService) AddAPI(api fr.API) error { - return ads.router.PutAPI(api) +func (l *LocalMemoryAPIDiscoveryService) AddAPI(api fr.API) error { + return l.router.PutAPI(api) } // GetAPI returns the method to the caller -func (ads *LocalMemoryAPIDiscoveryService) GetAPI(url string, httpVerb config.HTTPVerb) (fr.API, error) { - if api, ok := ads.router.FindAPI(url, httpVerb); ok { +func (l *LocalMemoryAPIDiscoveryService) GetAPI(url string, httpVerb config.HTTPVerb) (fr.API, error) { + if api, ok := l.router.FindAPI(url, httpVerb); ok { return *api, nil } @@ -68,80 +71,79 @@ func (ads *LocalMemoryAPIDiscoveryService) GetAPI(url string, httpVerb config.HT } // ClearAPI clear all api -func (ads *LocalMemoryAPIDiscoveryService) ClearAPI() error { - ads.router.ClearAPI() - return nil +func (l *LocalMemoryAPIDiscoveryService) ClearAPI() error { + return l.router.ClearAPI() } // RemoveAPIByPath remove all api belonged to path -func (ads *LocalMemoryAPIDiscoveryService) RemoveAPIByPath(deleted config.Resource) error { +func (l *LocalMemoryAPIDiscoveryService) RemoveAPIByPath(deleted config.Resource) error { _, groupPath := getDefaultPath() fullPath := getFullPath(groupPath, deleted.Path) - ads.router.DeleteNode(fullPath) + l.router.DeleteNode(fullPath) return nil } // RemoveAPIByPath remove all api -func (ads *LocalMemoryAPIDiscoveryService) RemoveAPI(fullPath string, method config.Method) error { - ads.router.DeleteAPI(fullPath, method.HTTPVerb) +func (l *LocalMemoryAPIDiscoveryService) RemoveAPI(fullPath string, method config.Method) error { + l.router.DeleteAPI(fullPath, method.HTTPVerb) return nil } // ResourceChange handle modify resource event -func (ads *LocalMemoryAPIDiscoveryService) ResourceChange(new config.Resource, old config.Resource) bool { - if err := modifyAPIFromResource(new, old, ads); err == nil { +func (l *LocalMemoryAPIDiscoveryService) ResourceChange(new config.Resource, old config.Resource) bool { + if err := modifyAPIFromResource(new, old, l); err == nil { return true } return false } // ResourceAdd handle add resource event -func (ads *LocalMemoryAPIDiscoveryService) ResourceAdd(res config.Resource) bool { +func (l *LocalMemoryAPIDiscoveryService) ResourceAdd(res config.Resource) bool { parentPath, groupPath := getDefaultPath() fullHeaders := make(map[string]string, 9) - if err := addAPIFromResource(res, ads, groupPath, parentPath, fullHeaders); err == nil { + if err := addAPIFromResource(res, l, groupPath, parentPath, fullHeaders); err == nil { return true } return false } // ResourceDelete handle delete resource event -func (ads *LocalMemoryAPIDiscoveryService) ResourceDelete(deleted config.Resource) bool { - if err := deleteAPIFromResource(deleted, ads); err == nil { +func (l *LocalMemoryAPIDiscoveryService) ResourceDelete(deleted config.Resource) bool { + if err := deleteAPIFromResource(deleted, l); err == nil { return true } return false } // MethodChange handle modify method event -func (ads *LocalMemoryAPIDiscoveryService) MethodChange(res config.Resource, new config.Method, old config.Method) bool { +func (l *LocalMemoryAPIDiscoveryService) MethodChange(res config.Resource, new config.Method, old config.Method) bool { _, groupPath := getDefaultPath() fullPath := getFullPath(groupPath, res.Path) fullHeaders := make(map[string]string, 9) - if err := modifyAPIFromMethod(fullPath, new, old, fullHeaders, ads); err == nil { + if err := modifyAPIFromMethod(fullPath, new, old, fullHeaders, l); err == nil { return true } return false } // MethodAdd handle add method event -func (ads *LocalMemoryAPIDiscoveryService) MethodAdd(res config.Resource, method config.Method) bool { +func (l *LocalMemoryAPIDiscoveryService) MethodAdd(res config.Resource, method config.Method) bool { _, groupPath := getDefaultPath() fullPath := getFullPath(groupPath, res.Path) fullHeaders := make(map[string]string, 9) - if err := addAPIFromMethod(fullPath, method, fullHeaders, ads); err == nil { + if err := addAPIFromMethod(fullPath, method, fullHeaders, l); err == nil { return true } return false } // MethodDelete handle delete method event -func (ads *LocalMemoryAPIDiscoveryService) MethodDelete(res config.Resource, method config.Method) bool { +func (l *LocalMemoryAPIDiscoveryService) MethodDelete(res config.Resource, method config.Method) bool { _, groupPath := getDefaultPath() fullPath := getFullPath(groupPath, res.Path) - if err := deleteAPIFromMethod(fullPath, method, ads); err == nil { + if err := deleteAPIFromMethod(fullPath, method, l); err == nil { return true } return false @@ -269,3 +271,15 @@ func loadAPIFromMethods(fullPath string, methods []config.Method, headers map[st } return nil } + +func (l *LocalMemoryAPIDiscoveryService) PluginPathChange(filePath string) { + plugins.OnFilePathChange(filePath) +} + +func (l *LocalMemoryAPIDiscoveryService) PluginGroupChange(group []config.PluginsGroup) { + plugins.OnGroupUpdate(group) +} + +func (l *LocalMemoryAPIDiscoveryService) RateLimitChange(c *ratelimitConf.Config) { + ratelimit.OnUpdate(c) +} diff --git a/samples/dubbogo/simple/body/docker/docker-compose.yml b/samples/dubbogo/simple/body/docker/docker-compose.yml new file mode 100644 index 000000000..7ca8ee583 --- /dev/null +++ b/samples/dubbogo/simple/body/docker/docker-compose.yml @@ -0,0 +1,27 @@ +# +# Licensed to 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. Apache Software Foundation (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. +# + +version: '3' + +services: + zookeeper: + image: zookeeper + ports: + - 2181:2181 + restart: on-failure diff --git a/samples/dubbogo/simple/body/api_config.yaml b/samples/dubbogo/simple/body/pixiu/api_config.yaml similarity index 100% rename from samples/dubbogo/simple/body/api_config.yaml rename to samples/dubbogo/simple/body/pixiu/api_config.yaml diff --git a/samples/dubbogo/simple/body/conf.yaml b/samples/dubbogo/simple/body/pixiu/conf.yaml similarity index 100% rename from samples/dubbogo/simple/body/conf.yaml rename to samples/dubbogo/simple/body/pixiu/conf.yaml diff --git a/samples/dubbogo/simple/body/server/app/server.go b/samples/dubbogo/simple/body/server/app/server.go new file mode 100644 index 000000000..87ab7628f --- /dev/null +++ b/samples/dubbogo/simple/body/server/app/server.go @@ -0,0 +1,74 @@ +/* + * 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 main + +import ( + "fmt" + "os" + "os/signal" + "syscall" + "time" +) + +import ( + "github.com/apache/dubbo-go/common/logger" + "github.com/apache/dubbo-go/config" + _ "github.com/apache/dubbo-go/protocol/dubbo" + _ "github.com/apache/dubbo-go/registry/protocol" + + _ "github.com/apache/dubbo-go/common/proxy/proxy_factory" + _ "github.com/apache/dubbo-go/filter/filter_impl" + + _ "github.com/apache/dubbo-go/cluster/cluster_impl" + _ "github.com/apache/dubbo-go/cluster/loadbalance" + _ "github.com/apache/dubbo-go/registry/zookeeper" +) + +var survivalTimeout = int(3e9) + +// they are necessary: +// export CONF_PROVIDER_FILE_PATH="xxx" +// export APP_LOG_CONF_FILE="xxx" +func main() { + config.Load() + logger.Info("dubbo version is: %s", Version) + initSignal() +} + +func initSignal() { + signals := make(chan os.Signal, 1) + // It is not possible to block SIGKILL or syscall.SIGSTOP + signal.Notify(signals, os.Interrupt, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT) + for { + sig := <-signals + logger.Infof("get signal %s", sig.String()) + switch sig { + case syscall.SIGHUP: + // reload() + default: + time.AfterFunc(time.Duration(survivalTimeout), func() { + logger.Warnf("app exit now by force...") + os.Exit(1) + }) + + // The program exits normally or timeout forcibly exits. + fmt.Println("provider app exit now...") + return + } + } +} diff --git a/samples/dubbogo/simple/body/server/app/user.go b/samples/dubbogo/simple/body/server/app/user.go new file mode 100644 index 000000000..e0f2b7da5 --- /dev/null +++ b/samples/dubbogo/simple/body/server/app/user.go @@ -0,0 +1,270 @@ +/* + * 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 main + +import ( + "context" + "errors" + "fmt" + "sync" + "time" +) + +import ( + hessian "github.com/apache/dubbo-go-hessian2" + "github.com/apache/dubbo-go/config" +) + +func init() { + config.SetProviderService(new(UserProvider)) + // ------for hessian2------ + hessian.RegisterPOJO(&User{}) + + cache = &UserDB{ + nameIndex: make(map[string]*User, 16), + codeIndex: make(map[int64]*User, 16), + lock: sync.Mutex{}, + } + + cache.Add(&User{ID: "0001", Code: 1, Name: "tc", Age: 18, Time: time.Now()}) + cache.Add(&User{ID: "0002", Code: 2, Name: "ic", Age: 88, Time: time.Now()}) +} + +var cache *UserDB + +// UserDB cache user. +type UserDB struct { + // key is name, value is user obj + nameIndex map[string]*User + // key is code, value is user obj + codeIndex map[int64]*User + lock sync.Mutex +} + +// nolint +func (db *UserDB) Add(u *User) bool { + db.lock.Lock() + defer db.lock.Unlock() + + if u.Name == "" || u.Code <= 0 { + return false + } + + if !db.existName(u.Name) && !db.existCode(u.Code) { + return db.AddForName(u) && db.AddForCode(u) + } + + return false +} + +// nolint +func (db *UserDB) AddForName(u *User) bool { + if len(u.Name) == 0 { + return false + } + + if _, ok := db.nameIndex[u.Name]; ok { + return false + } + + db.nameIndex[u.Name] = u + return true +} + +// nolint +func (db *UserDB) AddForCode(u *User) bool { + if u.Code <= 0 { + return false + } + + if _, ok := db.codeIndex[u.Code]; ok { + return false + } + + db.codeIndex[u.Code] = u + return true +} + +// nolint +func (db *UserDB) GetByName(n string) (*User, bool) { + db.lock.Lock() + defer db.lock.Unlock() + + r, ok := db.nameIndex[n] + return r, ok +} + +// nolint +func (db *UserDB) GetByCode(n int64) (*User, bool) { + db.lock.Lock() + defer db.lock.Unlock() + + r, ok := db.codeIndex[n] + return r, ok +} + +func (db *UserDB) existName(name string) bool { + if len(name) <= 0 { + return false + } + + _, ok := db.nameIndex[name] + if ok { + return true + } + + return false +} + +func (db *UserDB) existCode(code int64) bool { + if code <= 0 { + return false + } + + _, ok := db.codeIndex[code] + if ok { + return true + } + + return false +} + +// User user obj. +type User struct { + ID string `json:"id,omitempty"` + Code int64 `json:"code,omitempty"` + Name string `json:"name,omitempty"` + Age int32 `json:"age,omitempty"` + Time time.Time `json:"time,omitempty"` +} + +// UserProvider the dubbo provider. +// like: version: 1.0.0 group: test +type UserProvider struct{} + +// CreateUser new user, PX config POST. +func (u *UserProvider) CreateUser(ctx context.Context, user *User) (*User, error) { + outLn("Req CreateUser data:%#v", user) + if user == nil { + return nil, errors.New("not found") + } + _, ok := cache.GetByName(user.Name) + if ok { + return nil, errors.New("data is exist") + } + + b := cache.Add(user) + if b { + return user, nil + } + + return nil, errors.New("add error") +} + +// GetUserByName query by name, single param, PX config GET. +func (u *UserProvider) GetUserByName(ctx context.Context, name string) (*User, error) { + outLn("Req GetUserByName name:%#v", name) + r, ok := cache.GetByName(name) + if ok { + outLn("Req GetUserByName result:%#v", r) + return r, nil + } + return nil, nil +} + +// GetUserByCode query by code, single param, PX config GET. +func (u *UserProvider) GetUserByCode(ctx context.Context, code int64) (*User, error) { + outLn("Req GetUserByCode name:%#v", code) + r, ok := cache.GetByCode(code) + if ok { + outLn("Req GetUserByCode result:%#v", r) + return r, nil + } + return nil, nil +} + +// GetUserTimeout query by name, will timeout for pixiu. +func (u *UserProvider) GetUserTimeout(ctx context.Context, name string) (*User, error) { + outLn("Req GetUserByName name:%#v", name) + // sleep 10s, pixiu config less than 10s. + time.Sleep(10 * time.Second) + r, ok := cache.GetByName(name) + if ok { + outLn("Req GetUserByName result:%#v", r) + return r, nil + } + return nil, nil +} + +// GetUserByNameAndAge query by name and age, two params, PX config GET. +func (u *UserProvider) GetUserByNameAndAge(ctx context.Context, name string, age int32) (*User, error) { + outLn("Req GetUserByNameAndAge name:%s, age:%d", name, age) + r, ok := cache.GetByName(name) + if ok && r.Age == age { + outLn("Req GetUserByNameAndAge result:%#v", r) + return r, nil + } + return r, nil +} + +// UpdateUser update by user struct, my be another struct, PX config POST or PUT. +func (u *UserProvider) UpdateUser(ctx context.Context, user *User) (bool, error) { + outLn("Req UpdateUser data:%#v", user) + r, ok := cache.GetByName(user.Name) + if ok { + if user.ID != "" { + r.ID = user.ID + } + if user.Age >= 0 { + r.Age = user.Age + } + return true, nil + } + return false, errors.New("not found") +} + +// UpdateUserByName update by user struct, my be another struct, PX config POST or PUT. +func (u *UserProvider) UpdateUserByName(ctx context.Context, name string, user *User) (bool, error) { + outLn("Req UpdateUserByName data:%#v", user) + r, ok := cache.GetByName(name) + if ok { + if user.ID != "" { + r.ID = user.ID + } + if user.Age >= 0 { + r.Age = user.Age + } + return true, nil + } + return false, errors.New("not found") +} + +// nolint +func (u *UserProvider) Reference() string { + return "UserProvider" +} + +// nolint +func (u User) JavaClassName() string { + return "com.dubbogo.pixiu.User" +} + +// nolint +func outLn(format string, args ...interface{}) { + fmt.Printf("\033[32;40m"+format+"\033[0m\n", args...) +} diff --git a/samples/dubbogo/simple/body/server/app/version.go b/samples/dubbogo/simple/body/server/app/version.go new file mode 100644 index 000000000..04a3f7801 --- /dev/null +++ b/samples/dubbogo/simple/body/server/app/version.go @@ -0,0 +1,21 @@ +/* + * 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 main + +// Version dubbo version +const Version = "2.7.5" diff --git a/samples/dubbogo/simple/body/server/profiles/dev/log.yml b/samples/dubbogo/simple/body/server/profiles/dev/log.yml new file mode 100644 index 000000000..9330cda17 --- /dev/null +++ b/samples/dubbogo/simple/body/server/profiles/dev/log.yml @@ -0,0 +1,45 @@ +# +# 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. +# +level: "debug" +development: true +disableCaller: false +disableStacktrace: false +sampling: +encoding: "console" + +# encoder +encoderConfig: + messageKey: "message" + levelKey: "level" + timeKey: "time" + nameKey: "logger" + callerKey: "caller" + stacktraceKey: "stacktrace" + lineEnding: "" + levelEncoder: "capitalColor" + timeEncoder: "iso8601" + durationEncoder: "seconds" + callerEncoder: "short" + nameEncoder: "" + +outputPaths: + - "stderr" +errorOutputPaths: + - "stderr" +initialFields: diff --git a/samples/dubbogo/simple/body/server/profiles/dev/server.yml b/samples/dubbogo/simple/body/server/profiles/dev/server.yml new file mode 100644 index 000000000..66d8f949c --- /dev/null +++ b/samples/dubbogo/simple/body/server/profiles/dev/server.yml @@ -0,0 +1,73 @@ +# +# 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. +# +# dubbo server yaml configure file +# application config +application: + organization: "dubbogopixiu.com" + name: "BDTService" + module: "dubbogo user-info server" + version: "0.0.1" + owner: "ZX" + environment: "dev" + +registries: + "demoZk": + protocol: "zookeeper" + timeout: "3s" + address: "127.0.0.1:2181" + +services: + "UserProvider": + registry: "demoZk" + protocol: "dubbo" + # Equivalent to the interface in the dubbo.xml file + interface: "com.dubbogo.pixiu.UserService" + loadbalance: "random" + warmup: "100" + cluster: "failover" + group: test + version: 1.0.0 + methods: + - name: "CreateUser" + retries: 1 + loadbalance: "random" + +protocols: + "dubbo": + name: "dubbo" + port: 20000 + +protocol_conf: + dubbo: + session_number: 700 + session_timeout: "20s" + getty_session_param: + compress_encoding: false + tcp_no_delay: true + tcp_keep_alive: true + keep_alive_period: "120s" + tcp_r_buf_size: 262144 + tcp_w_buf_size: 65536 + pkg_rq_size: 1024 + pkg_wq_size: 512 + tcp_read_timeout: "1s" + tcp_write_timeout: "5s" + wait_timeout: "1s" + max_msg_len: 1024 + session_name: "server" \ No newline at end of file diff --git a/samples/dubbogo/simple/body/server/profiles/release/log.yml b/samples/dubbogo/simple/body/server/profiles/release/log.yml new file mode 100644 index 000000000..e2835d8f2 --- /dev/null +++ b/samples/dubbogo/simple/body/server/profiles/release/log.yml @@ -0,0 +1,45 @@ +# +# 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. +# +level: "warn" +development: true +disableCaller: true +disableStacktrace: true +sampling: +encoding: "console" + +# encoder +encoderConfig: + messageKey: "message" + levelKey: "level" + timeKey: "time" + nameKey: "logger" + callerKey: "caller" + stacktraceKey: "stacktrace" + lineEnding: "" + levelEncoder: "capitalColor" + timeEncoder: "iso8601" + durationEncoder: "seconds" + callerEncoder: "short" + nameEncoder: "" + +outputPaths: + - "stderr" +errorOutputPaths: + - "stderr" +initialFields: diff --git a/samples/dubbogo/simple/body/server/profiles/release/server.yml b/samples/dubbogo/simple/body/server/profiles/release/server.yml new file mode 100644 index 000000000..e4ebf01d1 --- /dev/null +++ b/samples/dubbogo/simple/body/server/profiles/release/server.yml @@ -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. +# +# dubbo server yaml configure file + + +# application config +application: + organization: "dubbogopixiu.com" + name: "BDTService" + module: "dubbogo user-info server" + version: "0.0.1" + owner: "ZX" + environment: "release" + +registries: + "hangzhouzk": + protocol: "zookeeper" + timeout: "3s" + address: "127.0.0.1:2181" + username: "" + password: "" + +services: + "UserProvider": + protocol: "dubbo" + # Equivalent to the interface in the dubbo.xml file + interface: "com.dubbogo.UserService" + loadbalance: "random" + warmup: "100" + cluster: "failover" + methods: + - name: "GetUser" + retries: 1 + loadbalance: "random" + + +protocols: + "dubbo": + name: "dubbo" + # ip : "127.0.0.1" + port: 20000 + + +protocol_conf: + dubbo: + session_number: 700 + session_timeout: "20s" + getty_session_param: + compress_encoding: false + tcp_no_delay: true + tcp_keep_alive: true + keep_alive_period: "120s" + tcp_r_buf_size: 262144 + tcp_w_buf_size: 65536 + pkg_rq_size: 1024 + pkg_wq_size: 512 + tcp_read_timeout: "1s" + tcp_write_timeout: "5s" + wait_timeout: "1s" + max_msg_len: 1024 + session_name: "server" \ No newline at end of file diff --git a/samples/dubbogo/simple/body/server/profiles/test/log.yml b/samples/dubbogo/simple/body/server/profiles/test/log.yml new file mode 100644 index 000000000..26d0a76ea --- /dev/null +++ b/samples/dubbogo/simple/body/server/profiles/test/log.yml @@ -0,0 +1,45 @@ +# +# 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. +# +level: "info" +development: false +disableCaller: false +disableStacktrace: true +sampling: +encoding: "console" + +# encoder +encoderConfig: + messageKey: "message" + levelKey: "level" + timeKey: "time" + nameKey: "logger" + callerKey: "caller" + stacktraceKey: "stacktrace" + lineEnding: "" + levelEncoder: "capitalColor" + timeEncoder: "iso8601" + durationEncoder: "seconds" + callerEncoder: "short" + nameEncoder: "" + +outputPaths: + - "stderr" +errorOutputPaths: + - "stderr" +initialFields: diff --git a/samples/dubbogo/simple/body/server/profiles/test/server.yml b/samples/dubbogo/simple/body/server/profiles/test/server.yml new file mode 100644 index 000000000..cba0212be --- /dev/null +++ b/samples/dubbogo/simple/body/server/profiles/test/server.yml @@ -0,0 +1,76 @@ +# +# 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. +# +# dubbo server yaml configure file + + +# application config +application: + organization: "dubbogopixiu.com" + name: "BDTService" + module: "dubbogo user-info server" + version: "0.0.1" + owner: "ZX" + environment: "test" + +registries: + "hangzhouzk": + protocol: "zookeeper" + timeout: "3s" + address: "127.0.0.1:2181" + username: "" + password: "" + +services: + "UserProvider": + protocol: "dubbo" + # Equivalent to the interface in the dubbo.xml file + interface: "com.dubbogo.UserService" + loadbalance: "random" + warmup: "100" + cluster: "failover" + methods: + - name: "GetUser" + retries: 1 + loadbalance: "random" + +protocols: + "dubbo": + name: "dubbo" + # ip : "127.0.0.1" + port: 20000 + + +protocol_conf: + dubbo: + session_number: 700 + session_timeout: "20s" + getty_session_param: + compress_encoding: false + tcp_no_delay: true + tcp_keep_alive: true + keep_alive_period: "120s" + tcp_r_buf_size: 262144 + tcp_w_buf_size: 65536 + pkg_rq_size: 1024 + pkg_wq_size: 512 + tcp_read_timeout: "1s" + tcp_write_timeout: "5s" + wait_timeout: "1s" + max_msg_len: 1024 + session_name: "server" \ No newline at end of file diff --git a/samples/dubbogo/simple/body/test/pixiu_test.go b/samples/dubbogo/simple/body/test/pixiu_test.go new file mode 100644 index 000000000..67469faaf --- /dev/null +++ b/samples/dubbogo/simple/body/test/pixiu_test.go @@ -0,0 +1,40 @@ +/* + * 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 test + +import ( + "bytes" + "net/http" + "testing" + "time" +) + +import ( + "github.com/stretchr/testify/assert" +) + +func TestPost(t *testing.T) { + var url = "http://localhost:8881/api/v1/test-dubbo/user" + data := "{\"id\":\"0003\",\"code\":3,\"name\":\"dubbogo\",\"age\":99}" + contentType := "application/json" + client := &http.Client{Timeout: 5 * time.Second} + resp, err := client.Post(url, contentType, bytes.NewBufferString(data)) + assert.NoError(t, err) + assert.NotNil(t, resp) + assert.Equal(t, 200, resp.StatusCode) +} diff --git a/start_integrate_test.sh b/start_integrate_test.sh new file mode 100644 index 000000000..625b65357 --- /dev/null +++ b/start_integrate_test.sh @@ -0,0 +1,35 @@ +# +# 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. + +array=("samples/dubbogo/simple/body") +#array+=("samples/dubbogo/simple/mix") +#array+=("samples/dubbogo/simple/proxy") +#array+=("samples/dubbogo/simple/query") +#array+=("samples/dubbogo/simple/server") +#array+=("samples/dubbogo/simple/uri") + +#http + + + +for((i=0;i<${#array[*]};i++)) +do + ./integrate_test.sh ${array[i]} + result=$? + if [ $result -gt 0 ]; then + exit $result + fi +done