├── files └── .placeholder ├── bundles ├── simple │ ├── go.mod │ ├── plugin_2.go │ ├── plugin_1.go │ └── manifest.json ├── README.md └── serverless-aws │ ├── manifest.json │ └── aws.go ├── util ├── init.go ├── storage │ ├── slave │ │ ├── models.go │ │ ├── conf.go │ │ └── slave.go │ ├── mongo │ │ ├── models.go │ │ ├── conf.go │ │ ├── mongo.go │ │ └── mserv_store.go │ ├── mock │ │ └── mock.go │ └── storage.go ├── logger │ └── logger.go └── conf │ └── config.go ├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── FEATURE.md │ └── BUG.md ├── .markdownlint.json ├── dependabot.yml ├── workflows │ ├── test.yaml │ ├── artifacts.yaml │ └── release.yml └── PULL_REQUEST_TEMPLATE.md ├── .markdownlint.json ├── mservctl ├── main.go └── cmd │ ├── delete.go │ ├── update.go │ ├── push.go │ ├── fetch.go │ ├── list.go │ └── root.go ├── .dockerignore ├── http_funcs ├── testdata │ ├── README.md │ └── uncompressed │ │ ├── manifest.json │ │ └── middleware.py ├── errors.go ├── endpoints.go ├── invocation.go ├── api_handlers_add_test.go ├── api_handlers_delete_test.go └── http_server.go ├── api ├── errors.go ├── loader_test.go ├── dispatcher.go └── loader.go ├── coprocess ├── dispatcher │ ├── init.go │ └── coprocess_grpc.go ├── models │ └── models.go └── bindings │ └── go │ ├── coprocess_return_overrides.pb.go │ └── coprocess_common.pb.go ├── .gitignore ├── CODEOWNERS ├── health └── health.go ├── mserv_example.conf ├── models └── payload.go ├── mserv_slave.json ├── conf ├── testdata │ └── mserv-conf.json ├── conf_test.go └── conf.go ├── mservclient ├── models │ ├── hook_type.go │ ├── hash_type.go │ ├── template_mode.go │ ├── auth_type_enum.go │ ├── id_extractor_type.go │ ├── middleware_driver.go │ ├── auth_provider_code.go │ ├── request_input_type.go │ ├── id_extractor_source.go │ ├── storage_engine_code.go │ ├── session_provider_code.go │ ├── tyk_event_handler_name.go │ ├── endpoint_method_action.go │ ├── m_i_m_e_header.go │ ├── routing_trigger_on_type.go │ ├── access_request_type.go │ ├── authorize_request_type.go │ ├── duration.go │ ├── h_report.go │ ├── internal_meta.go │ ├── check_command.go │ ├── access_spec.go │ ├── global_rate_limit.go │ ├── payload.go │ ├── string_regex_map.go │ ├── cache_meta.go │ ├── track_endpoint_meta.go │ ├── response_processor.go │ ├── o_id_provider_config.go │ ├── hard_timeout_meta.go │ ├── transform_j_q_meta.go │ ├── request_size_meta.go │ ├── method_transform_meta.go │ ├── return_overrides.go │ ├── middleware_definition.go │ ├── notifications_manager.go │ ├── header_injection_meta.go │ ├── circuit_breaker_meta.go │ ├── validate_path_meta.go │ ├── signature_config.go │ ├── virtual_meta.go │ ├── request_signing_meta.go │ ├── cache_options.go │ ├── api_limit.go │ ├── service_discovery_configuration.go │ ├── plugin.go │ ├── file_header.go │ ├── endpoint_method_meta.go │ ├── template_meta.go │ ├── event_handler_trigger_config.go │ ├── end_point_meta.go │ ├── bundle_manifest.go │ ├── open_id_options.go │ ├── auth_config.go │ ├── event_handler_meta_config.go │ └── url_rewrite_meta.go └── client │ ├── system │ ├── system_client.go │ └── health_parameters.go │ ├── invocation │ └── invocation_client.go │ └── mserv_api_client.go ├── docker-compose.yaml ├── storage ├── config_storage.go └── runtime_storage.go ├── Dockerfile ├── integration └── integration.yaml ├── .golangci.yaml ├── doc └── swagger.go └── Makefile /files/.placeholder: -------------------------------------------------------------------------------- 1 | required for local store to work -------------------------------------------------------------------------------- /bundles/simple/go.mod: -------------------------------------------------------------------------------- 1 | module tyk-plugin 2 | 3 | go 1.22.8 4 | -------------------------------------------------------------------------------- /util/init.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | func init() { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /bundles/README.md: -------------------------------------------------------------------------------- 1 | # Bundles 2 | 3 | Folder with example bundles used in integration tests. 4 | 5 | -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "default": true, 3 | "MD013": { 4 | "line_length": 120 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.github/.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.markdownlint.json", 3 | "MD013": false, 4 | "MD041": { 5 | "level": 2 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /mservctl/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/TykTechnologies/mserv/mservctl/cmd" 4 | 5 | func main() { 6 | cmd.Execute() 7 | } 8 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | # Binaries 2 | mserv 3 | mservctl 4 | 5 | # Makefile things 6 | /hack/bin/ 7 | /out/ 8 | /tmp/ 9 | 10 | # Git metadata 11 | .git 12 | .gitignore 13 | -------------------------------------------------------------------------------- /http_funcs/testdata/README.md: -------------------------------------------------------------------------------- 1 | # Test data 2 | 3 | Code taken from [this Tyk docs page](https://tyk.io/docs/tyk-cloud/configuration-options/using-plugins/python-code-bundle/). 4 | -------------------------------------------------------------------------------- /bundles/simple/plugin_2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | // AddHelloWorldHeader adds custom "Hello: World" header to the request 8 | func AddHelloWorldHeader(_ http.ResponseWriter, r *http.Request) { 9 | r.Header.Add("Hello", "World") 10 | } 11 | -------------------------------------------------------------------------------- /api/errors.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrCreateLocal = errors.New("could not create local directory for files") 7 | ErrFSKind = errors.New("storage kind not supported") 8 | ErrNoFSConfig = errors.New("no filestore configuration found") 9 | ) 10 | -------------------------------------------------------------------------------- /bundles/serverless-aws/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "file_list": [ 3 | "aws.so" 4 | ], 5 | "custom_middleware": { 6 | "post": [ 7 | { 8 | "name": "CallAWS" 9 | } 10 | ], 11 | "driver": "grpc" 12 | }, 13 | "checksum": "", 14 | "signature": "" 15 | } -------------------------------------------------------------------------------- /bundles/simple/plugin_1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | // AddFooBarHeader adds custom "Foo: Bar" header to the request 8 | func AddFooBarHeader(_ http.ResponseWriter, r *http.Request) { 9 | r.Header.Add("Foo", "Bar") 10 | } 11 | 12 | func main() {} 13 | -------------------------------------------------------------------------------- /coprocess/dispatcher/init.go: -------------------------------------------------------------------------------- 1 | package dispatcher 2 | 3 | func InitGlobalDispatch() { 4 | if GlobalDispatcher == nil { 5 | var err error 6 | GlobalDispatcher, err = NewCoProcessDispatcher() 7 | if err != nil { 8 | log.Error("failed to set global dispatcher: ", err) 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /api/loader_test.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import "testing" 4 | 5 | func TestPluginLoadAndDispatch(t *testing.T) { 6 | //d := Dispatcher{ 7 | // store: RuntimeStore{}, 8 | //} 9 | 10 | _, err := LoadPlugin("MyPreHook", "plugins/", "plugin.so") 11 | if err != nil { 12 | t.Fatal(err) 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries/objects 2 | bin/ 3 | mserv 4 | mservctl 5 | *.so 6 | 7 | # macOS 8 | .DS_Store 9 | 10 | # Miscellaneous 11 | build/bundle.zip 12 | bundle.zip 13 | client/client 14 | files/mserv-plugin-* 15 | hack 16 | mserv.json 17 | plugins 18 | integration/outputs/ 19 | 20 | # IDE resources 21 | .idea 22 | -------------------------------------------------------------------------------- /http_funcs/testdata/uncompressed/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "custom_middleware": { 3 | "auth_check": { 4 | "name": "MyAuthMiddleware" 5 | }, 6 | "driver": "python", 7 | "pre": [ 8 | { 9 | "name": "MyAuthMiddleware" 10 | } 11 | ] 12 | }, 13 | "file_list": ["middleware.py"] 14 | } 15 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners 2 | 3 | # These owners will be the default owners for everything in the repo. 4 | # 5 | # Unless a later match takes precedence, the Architect Back End team will be 6 | # requested for review when someone opens a pull request. 7 | 8 | * @TykTechnologies/cloud-squad-be 9 | -------------------------------------------------------------------------------- /health/health.go: -------------------------------------------------------------------------------- 1 | package health 2 | 3 | type HReport struct { 4 | HTTPStarted bool 5 | GRPCStarted bool 6 | } 7 | 8 | var Report = HReport{} 9 | 10 | func HttpStarted() { 11 | Report.HTTPStarted = true 12 | } 13 | 14 | func HttpStopped() { 15 | Report.HTTPStarted = false 16 | } 17 | 18 | func GrpcStarted() { 19 | Report.GRPCStarted = true 20 | } 21 | 22 | func GrpcStopped() { 23 | Report.GRPCStarted = false 24 | } 25 | -------------------------------------------------------------------------------- /mserv_example.conf: -------------------------------------------------------------------------------- 1 | { 2 | "Mserv": { 3 | "StorageTag": "default", 4 | "StoreType": "Mongo", 5 | "PluginDir": "~/downloads", 6 | "AllowHttpInvocation": false, 7 | "HTTPAddr": ":8989", 8 | "GrpcAddr": "", 9 | "PublicKeyPath": "", 10 | "MiddlewarePath": "~/plugins", 11 | "RetainUploads": false 12 | }, 13 | "MongoStore": { 14 | "default": { 15 | "ConnStr": "mongodb://mongodb:27017/admin" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /models/payload.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type BasePayload struct { 4 | Status string 5 | Error string 6 | } 7 | 8 | // Payload is the default response 9 | type Payload struct { 10 | Payload interface{} 11 | BasePayload 12 | } 13 | 14 | // NewPayload populates and returns an initialised Payload struct. 15 | func NewPayload(status string, payload interface{}, err string) Payload { 16 | return Payload{ 17 | BasePayload: BasePayload{ 18 | Status: status, 19 | Error: err, 20 | }, 21 | Payload: payload, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /util/storage/slave/models.go: -------------------------------------------------------------------------------- 1 | package slave 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | clientmodels "github.com/TykTechnologies/mserv/mservclient/models" 7 | "github.com/TykTechnologies/mserv/storage" 8 | ) 9 | 10 | func clientToStorageMW(clientMw *clientmodels.MW) (*storage.MW, error) { 11 | marshalled, err := clientMw.MarshalBinary() 12 | if err != nil { 13 | return nil, err 14 | } 15 | 16 | mw := &storage.MW{} 17 | if err := json.Unmarshal(marshalled, mw); err != nil { 18 | return nil, err 19 | } 20 | 21 | return mw, nil 22 | } 23 | -------------------------------------------------------------------------------- /util/storage/mongo/models.go: -------------------------------------------------------------------------------- 1 | package mongo 2 | 3 | import ( 4 | "errors" 5 | 6 | "go.mongodb.org/mongo-driver/bson/primitive" 7 | 8 | mservStorage "github.com/TykTechnologies/mserv/storage" 9 | ) 10 | 11 | type mgoMW struct { 12 | *mservStorage.MW 13 | MID primitive.ObjectID `bson:"_id"` 14 | } 15 | 16 | var ( 17 | // ErrEmptyUID is returned when middleware UID is empty. 18 | ErrEmptyUID = errors.New("UID cannot be empty") 19 | 20 | // ErrNotFound is returned when middleware is not found. 21 | ErrNotFound = errors.New("middleware not found") 22 | ) 23 | -------------------------------------------------------------------------------- /mserv_slave.json: -------------------------------------------------------------------------------- 1 | { 2 | "Mserv": { 3 | "StorageTag": "default", 4 | "StoreType": "Service", 5 | "PluginDir": "/downloads", 6 | "AllowHttpInvocation": false, 7 | "HTTPAddr": ":9090", 8 | "GrpcAddr": ":9191", 9 | "PublicKeyPath": "", 10 | "MiddlewarePath": "/plugins", 11 | "RetainUploads": false 12 | }, 13 | "MongoStore": { 14 | "default": { 15 | "ConnStr": "mongodb://mongodb:27017/admin" 16 | } 17 | }, 18 | "ServiceStore": { 19 | "default": { 20 | "ConnStr": "http://localhost:8989" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /conf/testdata/mserv-conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "Mserv": { 3 | "AllowHttpInvocation": false, 4 | "FileStore": { 5 | "Kind": "s3", 6 | "S3": { 7 | "ConfigAccessKeyID": "ALJBRQC3V5M8TCZHEO66", 8 | "ConfigRegion": "eu-west-2", 9 | "ConfigSecretKey": "75oIcEsaTcgeBlvEIyZQMy6DvvNtn7SrTjKbTbFq" 10 | } 11 | }, 12 | "Grpc": { 13 | "Address": ":9898", 14 | "Enabled": false 15 | }, 16 | "MiddlewarePath": "/mnt/mserv/plugins", 17 | "PublicKeyPath": "", 18 | "StorageTag": "default", 19 | "StoreType": "Mongo" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /http_funcs/errors.go: -------------------------------------------------------------------------------- 1 | package http_funcs //nolint:golint,stylecheck // We really should refactor this package name one day. 2 | 3 | import "errors" 4 | 5 | const ( 6 | // The http.DetectContentType func falls back to this MIME type if it cannot determine a more specific one. 7 | mimeGeneric = `application/octet-stream` 8 | mimeZIP = `application/zip` 9 | ) 10 | 11 | var ( 12 | ErrGenericMimeDetected = errors.New("the generic '" + mimeGeneric + "' MIME type was detected which is unsupported") 13 | ErrUploadNotZip = errors.New("uploaded file was not of '" + mimeZIP + "' MIME type") 14 | ) 15 | -------------------------------------------------------------------------------- /util/storage/mongo/conf.go: -------------------------------------------------------------------------------- 1 | package mongo 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/TykTechnologies/mserv/util/conf" 7 | ) 8 | 9 | type ( 10 | MgoStoreConf struct { 11 | ConnStr string 12 | } 13 | 14 | Config struct { 15 | MongoStore map[string]*MgoStoreConf 16 | } 17 | ) 18 | 19 | var sconf *Config 20 | 21 | var GetConf = func() *Config { 22 | if sconf == nil { 23 | sconf = &Config{} 24 | 25 | err := json.Unmarshal(conf.ReadConf(), sconf) 26 | if err != nil { 27 | log.Fatal("Failed to unmarshal mongo driver config: ", err) 28 | } 29 | } 30 | 31 | return sconf 32 | } 33 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 2 3 | 4 | updates: 5 | # GitHub Actions 6 | - package-ecosystem: github-actions 7 | directory: / 8 | schedule: 9 | interval: weekly 10 | commit-message: 11 | include: scope 12 | prefix: "Actions" 13 | reviewers: 14 | - "TykTechnologies/cloud-squad-be" 15 | 16 | # Go code base 17 | - package-ecosystem: gomod 18 | directory: / 19 | schedule: 20 | interval: weekly 21 | commit-message: 22 | include: scope 23 | prefix: "Go" 24 | reviewers: 25 | - "TykTechnologies/cloud-squad-be" 26 | open-pull-requests-limit: 10 27 | -------------------------------------------------------------------------------- /bundles/simple/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "file_list": [ 3 | "plugin_1_v5.6.1_linux_amd64.so", 4 | "plugin_2_v5.6.1_linux_amd64.so" 5 | ], 6 | "custom_middleware": { 7 | "pre": [ 8 | { 9 | "name": "AddFooBarHeader", 10 | "path": "plugin_1_v5.6.1_linux_amd64.so", 11 | "require_session": false, 12 | "raw_body_only": false 13 | }, 14 | { 15 | "name": "AddHelloWorldHeader", 16 | "path": "plugin_2_v5.6.1_linux_amd64.so", 17 | "require_session": false, 18 | "raw_body_only": false 19 | } 20 | ], 21 | "driver": "goplugin" 22 | }, 23 | "checksum": "", 24 | "signature": "" 25 | } 26 | -------------------------------------------------------------------------------- /util/storage/slave/conf.go: -------------------------------------------------------------------------------- 1 | package slave 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/TykTechnologies/mserv/util/conf" 6 | ) 7 | 8 | type StoreConf struct { 9 | ConnStr string 10 | Secret string 11 | } 12 | 13 | type Config struct { 14 | ServiceStore map[string]*StoreConf 15 | } 16 | 17 | var sconf *Config 18 | 19 | // Variable so we can override 20 | var GetConf = func() *Config { 21 | if sconf == nil { 22 | sconf = &Config{} 23 | 24 | err := json.Unmarshal(conf.ReadConf(), sconf) 25 | if err != nil { 26 | log.Fatal("Failed to unmarshal slave driver config: ", err) 27 | } 28 | 29 | SetDefaults() 30 | } 31 | 32 | return sconf 33 | } 34 | 35 | func SetDefaults() { 36 | // Set Defaults? 37 | } 38 | -------------------------------------------------------------------------------- /mservclient/models/hook_type.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | ) 13 | 14 | // HookType hook type 15 | // 16 | // swagger:model HookType 17 | type HookType int32 18 | 19 | // Validate validates this hook type 20 | func (m HookType) Validate(formats strfmt.Registry) error { 21 | return nil 22 | } 23 | 24 | // ContextValidate validates this hook type based on context it is used 25 | func (m HookType) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /mservclient/models/hash_type.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | ) 13 | 14 | // HashType hash type 15 | // 16 | // swagger:model HashType 17 | type HashType string 18 | 19 | // Validate validates this hash type 20 | func (m HashType) Validate(formats strfmt.Registry) error { 21 | return nil 22 | } 23 | 24 | // ContextValidate validates this hash type based on context it is used 25 | func (m HashType) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /http_funcs/testdata/uncompressed/middleware.py: -------------------------------------------------------------------------------- 1 | from tyk.decorators import * 2 | from gateway import TykGateway as tyk 3 | 4 | 5 | @Hook 6 | def MyAuthMiddleware(request, session, metadata, spec): 7 | auth = request.get_header('Authorization') 8 | if not auth: 9 | auth = request.object.params.get('authorization', None) 10 | 11 | if auth == '47a0c79c427728b3df4af62b9228c8ae': 12 | session.rate = 1000.0 13 | session.per = 1.0 14 | metadata["token"] = auth 15 | return request, session, metadata 16 | 17 | 18 | @Hook 19 | def MyPostMiddleware(request, session, spec): 20 | tyk.log("This is my post middleware", "info") 21 | request.object.set_headers["x-tyk-request"] = "something" 22 | return request, session 23 | -------------------------------------------------------------------------------- /mservclient/models/template_mode.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | ) 13 | 14 | // TemplateMode template mode 15 | // 16 | // swagger:model TemplateMode 17 | type TemplateMode string 18 | 19 | // Validate validates this template mode 20 | func (m TemplateMode) Validate(formats strfmt.Registry) error { 21 | return nil 22 | } 23 | 24 | // ContextValidate validates this template mode based on context it is used 25 | func (m TemplateMode) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /mservclient/models/auth_type_enum.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | ) 13 | 14 | // AuthTypeEnum auth type enum 15 | // 16 | // swagger:model AuthTypeEnum 17 | type AuthTypeEnum string 18 | 19 | // Validate validates this auth type enum 20 | func (m AuthTypeEnum) Validate(formats strfmt.Registry) error { 21 | return nil 22 | } 23 | 24 | // ContextValidate validates this auth type enum based on context it is used 25 | func (m AuthTypeEnum) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /mservclient/models/id_extractor_type.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | ) 13 | 14 | // IDExtractorType Id extractor type 15 | // 16 | // swagger:model IdExtractorType 17 | type IDExtractorType string 18 | 19 | // Validate validates this Id extractor type 20 | func (m IDExtractorType) Validate(formats strfmt.Registry) error { 21 | return nil 22 | } 23 | 24 | // ContextValidate validates this Id extractor type based on context it is used 25 | func (m IDExtractorType) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /mservclient/models/middleware_driver.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | ) 13 | 14 | // MiddlewareDriver middleware driver 15 | // 16 | // swagger:model MiddlewareDriver 17 | type MiddlewareDriver string 18 | 19 | // Validate validates this middleware driver 20 | func (m MiddlewareDriver) Validate(formats strfmt.Registry) error { 21 | return nil 22 | } 23 | 24 | // ContextValidate validates this middleware driver based on context it is used 25 | func (m MiddlewareDriver) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: Test, Lint, Build 2 | 3 | on: [push] 4 | 5 | jobs: 6 | tests: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v4 11 | 12 | - name: Setup Go 13 | uses: actions/setup-go@v5 14 | with: 15 | go-version: "1.22" 16 | 17 | - name: Test 18 | run: make test 19 | 20 | - name: Build server and client 21 | run: make build 22 | 23 | - name: Start Docker Compose with MongoDB and Tyk Mserv 24 | run: make start 25 | 26 | - name: Build and bundle plugins 27 | run: | 28 | make plugins 29 | make bundles 30 | 31 | - name: Install Venom command line tool 32 | run: go install github.com/ovh/venom/cmd/venom@latest 33 | 34 | - name: Run Venom tests 35 | run: make integration 36 | -------------------------------------------------------------------------------- /mservclient/models/auth_provider_code.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | ) 13 | 14 | // AuthProviderCode auth provider code 15 | // 16 | // swagger:model AuthProviderCode 17 | type AuthProviderCode string 18 | 19 | // Validate validates this auth provider code 20 | func (m AuthProviderCode) Validate(formats strfmt.Registry) error { 21 | return nil 22 | } 23 | 24 | // ContextValidate validates this auth provider code based on context it is used 25 | func (m AuthProviderCode) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /mservclient/models/request_input_type.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | ) 13 | 14 | // RequestInputType request input type 15 | // 16 | // swagger:model RequestInputType 17 | type RequestInputType string 18 | 19 | // Validate validates this request input type 20 | func (m RequestInputType) Validate(formats strfmt.Registry) error { 21 | return nil 22 | } 23 | 24 | // ContextValidate validates this request input type based on context it is used 25 | func (m RequestInputType) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /mservclient/models/id_extractor_source.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | ) 13 | 14 | // IDExtractorSource Id extractor source 15 | // 16 | // swagger:model IdExtractorSource 17 | type IDExtractorSource string 18 | 19 | // Validate validates this Id extractor source 20 | func (m IDExtractorSource) Validate(formats strfmt.Registry) error { 21 | return nil 22 | } 23 | 24 | // ContextValidate validates this Id extractor source based on context it is used 25 | func (m IDExtractorSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /mservclient/models/storage_engine_code.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | ) 13 | 14 | // StorageEngineCode storage engine code 15 | // 16 | // swagger:model StorageEngineCode 17 | type StorageEngineCode string 18 | 19 | // Validate validates this storage engine code 20 | func (m StorageEngineCode) Validate(formats strfmt.Registry) error { 21 | return nil 22 | } 23 | 24 | // ContextValidate validates this storage engine code based on context it is used 25 | func (m StorageEngineCode) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /mservclient/models/session_provider_code.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | ) 13 | 14 | // SessionProviderCode session provider code 15 | // 16 | // swagger:model SessionProviderCode 17 | type SessionProviderCode string 18 | 19 | // Validate validates this session provider code 20 | func (m SessionProviderCode) Validate(formats strfmt.Registry) error { 21 | return nil 22 | } 23 | 24 | // ContextValidate validates this session provider code based on context it is used 25 | func (m SessionProviderCode) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /mservclient/models/tyk_event_handler_name.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | ) 13 | 14 | // TykEventHandlerName tyk event handler name 15 | // 16 | // swagger:model TykEventHandlerName 17 | type TykEventHandlerName string 18 | 19 | // Validate validates this tyk event handler name 20 | func (m TykEventHandlerName) Validate(formats strfmt.Registry) error { 21 | return nil 22 | } 23 | 24 | // ContextValidate validates this tyk event handler name based on context it is used 25 | func (m TykEventHandlerName) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /mservclient/models/endpoint_method_action.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | ) 13 | 14 | // EndpointMethodAction endpoint method action 15 | // 16 | // swagger:model EndpointMethodAction 17 | type EndpointMethodAction string 18 | 19 | // Validate validates this endpoint method action 20 | func (m EndpointMethodAction) Validate(formats strfmt.Registry) error { 21 | return nil 22 | } 23 | 24 | // ContextValidate validates this endpoint method action based on context it is used 25 | func (m EndpointMethodAction) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /mservclient/models/m_i_m_e_header.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | ) 13 | 14 | // MIMEHeader A MIMEHeader represents a MIME-style header mapping 15 | // keys to sets of values. 16 | // 17 | // swagger:model MIMEHeader 18 | type MIMEHeader map[string][]string 19 | 20 | // Validate validates this m i m e header 21 | func (m MIMEHeader) Validate(formats strfmt.Registry) error { 22 | return nil 23 | } 24 | 25 | // ContextValidate validates this m i m e header based on context it is used 26 | func (m MIMEHeader) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 27 | return nil 28 | } 29 | -------------------------------------------------------------------------------- /mservclient/models/routing_trigger_on_type.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | ) 13 | 14 | // RoutingTriggerOnType routing trigger on type 15 | // 16 | // swagger:model RoutingTriggerOnType 17 | type RoutingTriggerOnType string 18 | 19 | // Validate validates this routing trigger on type 20 | func (m RoutingTriggerOnType) Validate(formats strfmt.Registry) error { 21 | return nil 22 | } 23 | 24 | // ContextValidate validates this routing trigger on type based on context it is used 25 | func (m RoutingTriggerOnType) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /mservclient/models/access_request_type.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | ) 13 | 14 | // AccessRequestType AccessRequestType is the type for OAuth param `grant_type` 15 | // 16 | // swagger:model AccessRequestType 17 | type AccessRequestType string 18 | 19 | // Validate validates this access request type 20 | func (m AccessRequestType) Validate(formats strfmt.Registry) error { 21 | return nil 22 | } 23 | 24 | // ContextValidate validates this access request type based on context it is used 25 | func (m AccessRequestType) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /util/logger/logger.go: -------------------------------------------------------------------------------- 1 | // Package logger provides a centralised logger resource. 2 | package logger 3 | 4 | import ( 5 | "os" 6 | "strings" 7 | 8 | "github.com/sirupsen/logrus" 9 | ) 10 | 11 | // GetLogger will provide a tagged logger by passing in a 'tag' value for easier log parsing. 12 | func GetLogger(tag string) *logrus.Entry { 13 | lvl := os.Getenv("TYK_MSERV_LOGLEVEL") 14 | 15 | var level logrus.Level 16 | switch strings.ToLower(lvl) { 17 | case "trace": 18 | level = logrus.TraceLevel 19 | case "debug": 20 | level = logrus.DebugLevel 21 | case "warning": 22 | level = logrus.WarnLevel 23 | case "error": 24 | level = logrus.ErrorLevel 25 | default: 26 | level = logrus.InfoLevel 27 | } 28 | 29 | logger := logrus.New() 30 | logger.SetLevel(level) 31 | logger.SetReportCaller(level >= logrus.DebugLevel) 32 | 33 | return logger.WithField("app", tag) 34 | } 35 | -------------------------------------------------------------------------------- /mservclient/models/authorize_request_type.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | ) 13 | 14 | // AuthorizeRequestType AuthorizeRequestType is the type for OAuth param `response_type` 15 | // 16 | // swagger:model AuthorizeRequestType 17 | type AuthorizeRequestType string 18 | 19 | // Validate validates this authorize request type 20 | func (m AuthorizeRequestType) Validate(formats strfmt.Registry) error { 21 | return nil 22 | } 23 | 24 | // ContextValidate validates this authorize request type based on context it is used 25 | func (m AuthorizeRequestType) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /mservclient/models/duration.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | ) 13 | 14 | // Duration A Duration represents the elapsed time between two instants 15 | // as an int64 nanosecond count. The representation limits the 16 | // largest representable duration to approximately 290 years. 17 | // 18 | // swagger:model Duration 19 | type Duration int64 20 | 21 | // Validate validates this duration 22 | func (m Duration) Validate(formats strfmt.Registry) error { 23 | return nil 24 | } 25 | 26 | // ContextValidate validates this duration based on context it is used 27 | func (m Duration) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 28 | return nil 29 | } 30 | -------------------------------------------------------------------------------- /mservctl/cmd/delete.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "github.com/TykTechnologies/mserv/mservclient/client/mw" 5 | "github.com/spf13/cobra" 6 | ) 7 | 8 | // deleteCmd represents the delete command 9 | var deleteCmd = &cobra.Command{ 10 | Use: "delete", 11 | Short: "Deletes a middleware from mserv", 12 | Long: `Deletes a middleware record by ID, e.g.: 13 | 14 | $ mservctl delete 13b0eb10-419f-40ef-838d-6d26bb2eeaa8`, 15 | Args: cobra.ExactArgs(1), 16 | Run: deleteMiddleware, 17 | } 18 | 19 | func init() { 20 | rootCmd.AddCommand(deleteCmd) 21 | } 22 | 23 | func deleteMiddleware(cmd *cobra.Command, args []string) { 24 | params := mw.NewMwDeleteParams().WithID(args[0]) 25 | resp, err := mservapi.Mw.MwDelete(params, defaultAuth()) 26 | if err != nil { 27 | log.WithError(err).Error("Couldn't delete middleware") 28 | return 29 | } 30 | 31 | cmd.Printf("Middleware deleted successfully, ID: %s\n", resp.GetPayload().Payload.BundleID) 32 | } 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/FEATURE.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🚀 Feature request 3 | about: Suggest an idea for this project 4 | labels: enhancement 5 | assignees: # TODO(jlucktay): populate with team(s) once https://github.com/dear-github/dear-github/issues/170 is done 6 | --- 7 | 8 | 9 | 10 | ## Expected Behavior 11 | 12 | 13 | ## Current Behavior 14 | 15 | 16 | 17 | ## Possible Solution 18 | 19 | 20 | ## Additional Context 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | version: '3.8' 3 | 4 | services: 5 | tyk-plugin-compiler: 6 | image: tykio/tyk-plugin-compiler:${TYK_VERSION} 7 | platform: linux/amd64 8 | volumes: 9 | - ./bundles/simple:/plugin-source 10 | networks: 11 | - tyk 12 | 13 | tyk-gateway: 14 | image: tykio/tyk-gateway:${TYK_VERSION} 15 | platform: linux/amd64 16 | volumes: 17 | - ./bundles/simple:/plugin-source 18 | networks: 19 | - tyk 20 | 21 | mongodb: 22 | image: mongo:6.0 23 | restart: always 24 | environment: 25 | - AUTH=no 26 | volumes: 27 | - mongo-data:/data/db 28 | ports: 29 | - "27017:27017" 30 | networks: 31 | - tyk 32 | 33 | mserv: 34 | build: . 35 | restart: always 36 | volumes: 37 | - ./mserv_example.conf:/etc/mserv/mserv.json 38 | depends_on: 39 | - mongodb 40 | ports: 41 | - "8989:8989" 42 | networks: 43 | - tyk 44 | 45 | volumes: 46 | mongo-data: 47 | 48 | networks: 49 | tyk: 50 | -------------------------------------------------------------------------------- /http_funcs/endpoints.go: -------------------------------------------------------------------------------- 1 | package http_funcs 2 | 3 | import "github.com/gorilla/mux" 4 | 5 | var rt *mux.Router 6 | 7 | func GetRouter() *mux.Router { 8 | rt = mux.NewRouter() 9 | rt.Use(setupGlobalMiddleware) 10 | return rt 11 | } 12 | 13 | func InitEndpoints(r *mux.Router, serv *HttpServ) { 14 | // Health endpoint 15 | r.HandleFunc("/health", serv.HealthHandler).Methods("GET") 16 | } 17 | 18 | func InitHttpInvocationServer(r *mux.Router, serv *HttpServ) { 19 | // Invocation endpoints 20 | r.HandleFunc("/execute/{name}", serv.Execute).Methods("POST") 21 | } 22 | 23 | func InitAPI(r *mux.Router, serv *HttpServ) { 24 | r.HandleFunc("/api/mw/master/all", serv.FetchAllActiveMW).Methods("GET") 25 | r.HandleFunc("/api/mw/bundle/{id}", serv.FetchBundleFile).Methods("GET") 26 | r.HandleFunc("/api/mw/{id}", serv.UpdateMW).Methods("PUT") 27 | r.HandleFunc("/api/mw/{id}", serv.FetchMW).Methods("GET") 28 | r.HandleFunc("/api/mw/{id}", serv.DeleteMW).Methods("DELETE") 29 | r.HandleFunc("/api/mw", serv.AddMW).Methods("POST") 30 | } 31 | -------------------------------------------------------------------------------- /storage/config_storage.go: -------------------------------------------------------------------------------- 1 | package storage 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "github.com/TykTechnologies/tyk/apidef" 8 | 9 | coprocess "github.com/TykTechnologies/mserv/coprocess/bindings/go" 10 | ) 11 | 12 | type Plugin struct { 13 | UID string 14 | Name string 15 | FileName string 16 | FileRef string 17 | Type coprocess.HookType 18 | } 19 | 20 | type MW struct { 21 | Added time.Time 22 | Manifest *apidef.BundleManifest 23 | APIID string 24 | OrgID string 25 | UID string 26 | BundleRef string 27 | Plugins []*Plugin 28 | Active bool 29 | DownloadOnly bool 30 | } 31 | 32 | type MservStore interface { 33 | GetMWByID(ctx context.Context, id string) (*MW, error) 34 | GetMWByAPIID(ctx context.Context, APIID string) (*MW, error) 35 | GetAllActive(ctx context.Context) ([]*MW, error) 36 | CreateMW(ctx context.Context, mw *MW) (string, error) 37 | UpdateMW(ctx context.Context, mw *MW) (string, error) 38 | DeleteMW(ctx context.Context, id string) error 39 | InitMservStore(ctx context.Context, tag string) error 40 | } 41 | -------------------------------------------------------------------------------- /conf/conf_test.go: -------------------------------------------------------------------------------- 1 | package config_test 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/matryer/is" 8 | 9 | config "github.com/TykTechnologies/mserv/conf" 10 | ) 11 | 12 | // TestGetConf makes sure that envconfig defaults get overridden by values set (in order of preference) first in the 13 | // environment, and then second in the config file. 14 | func TestGetConf(t *testing.T) { 15 | is := is.New(t) 16 | is.NoErr(os.Setenv("TYK_MSERV_CONFIG", "testdata/mserv-conf.json")) 17 | is.NoErr(os.Setenv("MS_MSERV_RETAINUPLOADS", "true")) 18 | 19 | ms := config.GetConf() 20 | is.Equal(ms.Mserv.FileStore.Kind, "s3") // cfg.Mserv.FileStore.Kind mismatch 21 | is.Equal(ms.Mserv.FileStore.S3.ConfigRegion, "eu-west-2") // cfg.Mserv.FileStore.S3.ConfigRegion mismatch 22 | is.Equal(ms.Mserv.HTTPAddr, ":8989") // cfg.Mserv.HTTPAddr mismatch 23 | is.Equal(ms.Mserv.MiddlewarePath, "/mnt/mserv/plugins") // cfg.Mserv.MiddlewarePath mismatch 24 | is.Equal(ms.Mserv.PluginDir, "/tmp/mserv/plugins") // cfg.Mserv.PluginDir mismatch 25 | is.Equal(ms.Mserv.RetainUploads, true) // cfg.Mserv.RetainUploads mismatch 26 | } 27 | -------------------------------------------------------------------------------- /.github/workflows/artifacts.yaml: -------------------------------------------------------------------------------- 1 | name: Build and push docker image 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*" 7 | 8 | jobs: 9 | check-base-branch: 10 | runs-on: ubuntu-latest 11 | outputs: 12 | on_main: ${{ steps.contains_tag.outputs.retval }} 13 | steps: 14 | - name: Git checkout 15 | uses: actions/checkout@v4 16 | with: 17 | fetch-depth: 0 18 | 19 | - uses: rickstaa/action-contains-tag@v1 20 | id: contains_tag 21 | with: 22 | reference: "master" 23 | tag: "${{ github.ref }}" 24 | 25 | build-and-push: 26 | runs-on: ubuntu-latest 27 | needs: check-base-branch 28 | steps: 29 | - name: Git checkout 30 | uses: actions/checkout@v4 31 | 32 | - uses: TykTechnologies/actions/docker-login@main 33 | with: 34 | dockerhub_username: ${{ secrets.DOCKER_USERNAME }} 35 | dockerhub_token: ${{ secrets.DOCKER_PASSWORD }} 36 | 37 | - uses: TykTechnologies/actions/docker-build-push@main 38 | with: 39 | dockerfile: Dockerfile 40 | tags: ${{ github.ref_name }} 41 | platforms: linux/amd64,linux/arm64 42 | repository_name: mserv 43 | -------------------------------------------------------------------------------- /mservctl/cmd/update.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "os" 5 | "time" 6 | 7 | "github.com/spf13/cobra" 8 | 9 | "github.com/TykTechnologies/mserv/mservclient/client/mw" 10 | ) 11 | 12 | // updateCmd represents the update command 13 | var updateCmd = &cobra.Command{ 14 | Use: "update", 15 | Short: "Updates a middleware on mserv", 16 | Long: "Updates a middleware by ID", 17 | Example: `mservctl update 13b0eb10-419f-40ef-838d-6d26bb2eeaa8 /path/to/bundle.zip`, 18 | Args: cobra.ExactArgs(2), 19 | Run: updateMiddleware, 20 | } 21 | 22 | func init() { 23 | rootCmd.AddCommand(updateCmd) 24 | } 25 | 26 | func updateMiddleware(cmd *cobra.Command, args []string) { 27 | file, err := os.Open(args[1]) 28 | if err != nil { 29 | log.WithError(err).Error("Couldn't open the bundle file") 30 | return 31 | } 32 | defer file.Close() 33 | 34 | params := mw.NewMwUpdateParams().WithID(args[0]).WithUploadFile(file).WithTimeout(120 * time.Second) 35 | 36 | resp, err := mservapi.Mw.MwUpdate(params, defaultAuth()) 37 | if err != nil { 38 | log.WithError(err).Error("Couldn't update middleware") 39 | return 40 | } 41 | 42 | cmd.Printf("Middleware uploaded successfully, ID: %s\n", resp.GetPayload().Payload.BundleID) 43 | } 44 | -------------------------------------------------------------------------------- /http_funcs/invocation.go: -------------------------------------------------------------------------------- 1 | package http_funcs 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/TykTechnologies/mserv/api" 6 | "io/ioutil" 7 | "net/http" 8 | 9 | "github.com/TykTechnologies/mserv/coprocess/bindings/go" 10 | "golang.org/x/net/context" 11 | "time" 12 | ) 13 | 14 | // swagger:route POST /execute/{name} invocation invoke 15 | // Invokes a middleware by {name}. 16 | // Expects a coprocess.Object encoded as JSON in the request body and returns the result in the same way. 17 | // 18 | // Security: 19 | // api_key: 20 | // 21 | // Responses: 22 | // 200: invocationResponse 23 | // 500: genericErrorResponse 24 | func (h *HttpServ) Execute(w http.ResponseWriter, r *http.Request) { 25 | body, err := ioutil.ReadAll(r.Body) 26 | if err != nil { 27 | h.HandleError(err, w, r) 28 | return 29 | } 30 | 31 | cp := &coprocess.Object{} 32 | err = json.Unmarshal(body, cp) 33 | if err != nil { 34 | h.HandleError(err, w, r) 35 | return 36 | } 37 | 38 | d := api.Dispatcher{} 39 | ctx, cancel := context.WithTimeout(r.Context(), time.Second*5) 40 | defer cancel() 41 | 42 | retObj, err := d.Dispatch(ctx, cp) 43 | if err != nil { 44 | h.HandleError(err, w, r) 45 | return 46 | } 47 | 48 | h.HandleOK(retObj, w, r) 49 | } 50 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.22.8 AS builder 2 | 3 | # Set some shell options for using pipes and such 4 | SHELL [ "/bin/bash", "-euo", "pipefail", "-c" ] 5 | 6 | # Install common CA certificates to blag later 7 | RUN apt-get update \ 8 | && apt-get install --assume-yes --no-install-recommends ca-certificates \ 9 | && apt-get autoremove --assume-yes \ 10 | && rm -rf /root/.cache 11 | 12 | # Don't call any C code (the 'scratch' base image used later won't have any libraries to reference) 13 | ENV CGO_ENABLED=0 14 | 15 | WORKDIR /go/src/github.com/TykTechnologies/mserv 16 | 17 | COPY . . 18 | 19 | RUN go build -ldflags="-buildid= -w" -trimpath -v -o /bin/mserv 20 | RUN mkdir -p /opt/mserv/downloads /opt/mserv/plugins 21 | 22 | FROM gcr.io/distroless/base:nonroot AS runner 23 | USER 65532 24 | 25 | ENV TYK_MSERV_CONFIG /etc/mserv/mserv.json 26 | 27 | LABEL Description="Tyk MServ service docker image" Vendor="Tyk" Version=$TYKVERSION 28 | 29 | WORKDIR /opt/mserv 30 | 31 | # Bring common CA certificates and binary over. 32 | COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt 33 | COPY --from=builder /bin/mserv /opt/mserv/mserv 34 | COPY --from=builder /opt/mserv/downloads /opt/mserv/downloads 35 | COPY --from=builder /opt/mserv/plugins /opt/mserv/plugins 36 | 37 | ENTRYPOINT [ "/opt/mserv/mserv" ] 38 | -------------------------------------------------------------------------------- /api/dispatcher.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "fmt" 5 | "github.com/TykTechnologies/mserv/coprocess/bindings/go" 6 | "github.com/TykTechnologies/mserv/storage" 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | // Dispatcher implementation 11 | type Dispatcher struct{} 12 | 13 | // Dispatch will be called on every request: 14 | func (d *Dispatcher) Dispatch(ctx context.Context, object *coprocess.Object) (*coprocess.Object, error) { 15 | apiRef, ok := object.Spec["APIID"] 16 | if !ok { 17 | return object, fmt.Errorf("api ID not found in spec: %v", object.Spec) 18 | } 19 | 20 | orgRef, ok := object.Spec["OrgID"] 21 | if !ok { 22 | return object, fmt.Errorf("org ID not found in spec: %v", object.Spec) 23 | } 24 | 25 | storeKey := storage.GenerateStoreKey(orgRef, apiRef, object.HookType.String(), object.HookName) 26 | 27 | log.Warning("func called: ", storeKey) 28 | hook, err := storage.GlobalRtStore.GetHookFunc(storeKey) 29 | if err != nil { 30 | log.Warning("-- not found") 31 | return object, err 32 | } 33 | 34 | log.Warning("-- found, executing") 35 | return hook(object) 36 | } 37 | 38 | // DispatchEvent will be called when a Tyk event is triggered: 39 | func (d *Dispatcher) DispatchEvent(ctx context.Context, event *coprocess.Event) (*coprocess.EventReply, error) { 40 | return &coprocess.EventReply{}, nil 41 | } 42 | -------------------------------------------------------------------------------- /mservclient/models/h_report.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // HReport h report 16 | // 17 | // swagger:model HReport 18 | type HReport struct { 19 | 20 | // g RPC started 21 | GRPCStarted bool `json:"GRPCStarted,omitempty"` 22 | 23 | // HTTP started 24 | HTTPStarted bool `json:"HTTPStarted,omitempty"` 25 | } 26 | 27 | // Validate validates this h report 28 | func (m *HReport) Validate(formats strfmt.Registry) error { 29 | return nil 30 | } 31 | 32 | // ContextValidate validates this h report based on context it is used 33 | func (m *HReport) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 34 | return nil 35 | } 36 | 37 | // MarshalBinary interface implementation 38 | func (m *HReport) MarshalBinary() ([]byte, error) { 39 | if m == nil { 40 | return nil, nil 41 | } 42 | return swag.WriteJSON(m) 43 | } 44 | 45 | // UnmarshalBinary interface implementation 46 | func (m *HReport) UnmarshalBinary(b []byte) error { 47 | var res HReport 48 | if err := swag.ReadJSON(b, &res); err != nil { 49 | return err 50 | } 51 | *m = res 52 | return nil 53 | } 54 | -------------------------------------------------------------------------------- /mservclient/models/internal_meta.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // InternalMeta internal meta 16 | // 17 | // swagger:model InternalMeta 18 | type InternalMeta struct { 19 | 20 | // method 21 | Method string `json:"method,omitempty"` 22 | 23 | // path 24 | Path string `json:"path,omitempty"` 25 | } 26 | 27 | // Validate validates this internal meta 28 | func (m *InternalMeta) Validate(formats strfmt.Registry) error { 29 | return nil 30 | } 31 | 32 | // ContextValidate validates this internal meta based on context it is used 33 | func (m *InternalMeta) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 34 | return nil 35 | } 36 | 37 | // MarshalBinary interface implementation 38 | func (m *InternalMeta) MarshalBinary() ([]byte, error) { 39 | if m == nil { 40 | return nil, nil 41 | } 42 | return swag.WriteJSON(m) 43 | } 44 | 45 | // UnmarshalBinary interface implementation 46 | func (m *InternalMeta) UnmarshalBinary(b []byte) error { 47 | var res InternalMeta 48 | if err := swag.ReadJSON(b, &res); err != nil { 49 | return err 50 | } 51 | *m = res 52 | return nil 53 | } 54 | -------------------------------------------------------------------------------- /mservclient/models/check_command.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // CheckCommand check command 16 | // 17 | // swagger:model CheckCommand 18 | type CheckCommand struct { 19 | 20 | // message 21 | Message string `json:"message,omitempty"` 22 | 23 | // name 24 | Name string `json:"name,omitempty"` 25 | } 26 | 27 | // Validate validates this check command 28 | func (m *CheckCommand) Validate(formats strfmt.Registry) error { 29 | return nil 30 | } 31 | 32 | // ContextValidate validates this check command based on context it is used 33 | func (m *CheckCommand) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 34 | return nil 35 | } 36 | 37 | // MarshalBinary interface implementation 38 | func (m *CheckCommand) MarshalBinary() ([]byte, error) { 39 | if m == nil { 40 | return nil, nil 41 | } 42 | return swag.WriteJSON(m) 43 | } 44 | 45 | // UnmarshalBinary interface implementation 46 | func (m *CheckCommand) UnmarshalBinary(b []byte) error { 47 | var res CheckCommand 48 | if err := swag.ReadJSON(b, &res); err != nil { 49 | return err 50 | } 51 | *m = res 52 | return nil 53 | } 54 | -------------------------------------------------------------------------------- /coprocess/models/models.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "github.com/TykTechnologies/mserv/coprocess/bindings/go" 5 | "github.com/TykTechnologies/tyk/apidef" 6 | "github.com/TykTechnologies/tyk/user" 7 | ) 8 | 9 | const MWStatusRespond = 666 10 | 11 | // Lets the user override and return a response from middleware 12 | type ReturnOverrides struct { 13 | ResponseCode int 14 | ResponseError string 15 | ResponseHeaders map[string]string 16 | } 17 | 18 | // MiniRequestObject is marshalled to JSON string and passed into JSON middleware 19 | type MiniRequestObject struct { 20 | Headers map[string][]string 21 | SetHeaders map[string]string 22 | DeleteHeaders []string 23 | Body []byte 24 | URL string 25 | Params map[string][]string 26 | AddParams map[string]string 27 | ExtendedParams map[string][]string 28 | DeleteParams []string 29 | ReturnOverrides ReturnOverrides 30 | IgnoreBody bool 31 | Method string 32 | RequestURI string 33 | Scheme string 34 | } 35 | 36 | type VMReturnObject struct { 37 | Request MiniRequestObject 38 | SessionMeta map[string]string 39 | Session user.SessionState 40 | AuthValue string 41 | } 42 | 43 | type CoProcessMiddleware struct { 44 | HookType coprocess.HookType 45 | HookName string 46 | MiddlewareDriver string 47 | Spec *apidef.APIDefinition 48 | } 49 | -------------------------------------------------------------------------------- /mservclient/models/access_spec.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // AccessSpec AccessSpecs define what URLS a user has access to an what methods are enabled 16 | // 17 | // swagger:model AccessSpec 18 | type AccessSpec struct { 19 | 20 | // methods 21 | Methods []string `json:"methods"` 22 | 23 | // URL 24 | URL string `json:"url,omitempty"` 25 | } 26 | 27 | // Validate validates this access spec 28 | func (m *AccessSpec) Validate(formats strfmt.Registry) error { 29 | return nil 30 | } 31 | 32 | // ContextValidate validates this access spec based on context it is used 33 | func (m *AccessSpec) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 34 | return nil 35 | } 36 | 37 | // MarshalBinary interface implementation 38 | func (m *AccessSpec) MarshalBinary() ([]byte, error) { 39 | if m == nil { 40 | return nil, nil 41 | } 42 | return swag.WriteJSON(m) 43 | } 44 | 45 | // UnmarshalBinary interface implementation 46 | func (m *AccessSpec) UnmarshalBinary(b []byte) error { 47 | var res AccessSpec 48 | if err := swag.ReadJSON(b, &res); err != nil { 49 | return err 50 | } 51 | *m = res 52 | return nil 53 | } 54 | -------------------------------------------------------------------------------- /mservclient/models/global_rate_limit.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // GlobalRateLimit global rate limit 16 | // 17 | // swagger:model GlobalRateLimit 18 | type GlobalRateLimit struct { 19 | 20 | // per 21 | Per float64 `json:"per,omitempty"` 22 | 23 | // rate 24 | Rate float64 `json:"rate,omitempty"` 25 | } 26 | 27 | // Validate validates this global rate limit 28 | func (m *GlobalRateLimit) Validate(formats strfmt.Registry) error { 29 | return nil 30 | } 31 | 32 | // ContextValidate validates this global rate limit based on context it is used 33 | func (m *GlobalRateLimit) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 34 | return nil 35 | } 36 | 37 | // MarshalBinary interface implementation 38 | func (m *GlobalRateLimit) MarshalBinary() ([]byte, error) { 39 | if m == nil { 40 | return nil, nil 41 | } 42 | return swag.WriteJSON(m) 43 | } 44 | 45 | // UnmarshalBinary interface implementation 46 | func (m *GlobalRateLimit) UnmarshalBinary(b []byte) error { 47 | var res GlobalRateLimit 48 | if err := swag.ReadJSON(b, &res); err != nil { 49 | return err 50 | } 51 | *m = res 52 | return nil 53 | } 54 | -------------------------------------------------------------------------------- /mservclient/models/payload.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // Payload Payload is the default response 16 | // 17 | // swagger:model Payload 18 | type Payload struct { 19 | 20 | // error 21 | Error string `json:"Error,omitempty"` 22 | 23 | // payload 24 | Payload interface{} `json:"Payload,omitempty"` 25 | 26 | // status 27 | Status string `json:"Status,omitempty"` 28 | } 29 | 30 | // Validate validates this payload 31 | func (m *Payload) Validate(formats strfmt.Registry) error { 32 | return nil 33 | } 34 | 35 | // ContextValidate validates this payload based on context it is used 36 | func (m *Payload) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 37 | return nil 38 | } 39 | 40 | // MarshalBinary interface implementation 41 | func (m *Payload) MarshalBinary() ([]byte, error) { 42 | if m == nil { 43 | return nil, nil 44 | } 45 | return swag.WriteJSON(m) 46 | } 47 | 48 | // UnmarshalBinary interface implementation 49 | func (m *Payload) UnmarshalBinary(b []byte) error { 50 | var res Payload 51 | if err := swag.ReadJSON(b, &res); err != nil { 52 | return err 53 | } 54 | *m = res 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /mservclient/models/string_regex_map.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // StringRegexMap string regex map 16 | // 17 | // swagger:model StringRegexMap 18 | type StringRegexMap struct { 19 | 20 | // match pattern 21 | MatchPattern string `json:"match_rx,omitempty"` 22 | 23 | // reverse 24 | Reverse bool `json:"reverse,omitempty"` 25 | } 26 | 27 | // Validate validates this string regex map 28 | func (m *StringRegexMap) Validate(formats strfmt.Registry) error { 29 | return nil 30 | } 31 | 32 | // ContextValidate validates this string regex map based on context it is used 33 | func (m *StringRegexMap) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 34 | return nil 35 | } 36 | 37 | // MarshalBinary interface implementation 38 | func (m *StringRegexMap) MarshalBinary() ([]byte, error) { 39 | if m == nil { 40 | return nil, nil 41 | } 42 | return swag.WriteJSON(m) 43 | } 44 | 45 | // UnmarshalBinary interface implementation 46 | func (m *StringRegexMap) UnmarshalBinary(b []byte) error { 47 | var res StringRegexMap 48 | if err := swag.ReadJSON(b, &res); err != nil { 49 | return err 50 | } 51 | *m = res 52 | return nil 53 | } 54 | -------------------------------------------------------------------------------- /mservclient/models/cache_meta.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // CacheMeta cache meta 16 | // 17 | // swagger:model CacheMeta 18 | type CacheMeta struct { 19 | 20 | // cache key regex 21 | CacheKeyRegex string `json:"cache_key_regex,omitempty"` 22 | 23 | // method 24 | Method string `json:"method,omitempty"` 25 | 26 | // path 27 | Path string `json:"path,omitempty"` 28 | } 29 | 30 | // Validate validates this cache meta 31 | func (m *CacheMeta) Validate(formats strfmt.Registry) error { 32 | return nil 33 | } 34 | 35 | // ContextValidate validates this cache meta based on context it is used 36 | func (m *CacheMeta) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 37 | return nil 38 | } 39 | 40 | // MarshalBinary interface implementation 41 | func (m *CacheMeta) MarshalBinary() ([]byte, error) { 42 | if m == nil { 43 | return nil, nil 44 | } 45 | return swag.WriteJSON(m) 46 | } 47 | 48 | // UnmarshalBinary interface implementation 49 | func (m *CacheMeta) UnmarshalBinary(b []byte) error { 50 | var res CacheMeta 51 | if err := swag.ReadJSON(b, &res); err != nil { 52 | return err 53 | } 54 | *m = res 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /mservclient/models/track_endpoint_meta.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // TrackEndpointMeta track endpoint meta 16 | // 17 | // swagger:model TrackEndpointMeta 18 | type TrackEndpointMeta struct { 19 | 20 | // method 21 | Method string `json:"method,omitempty"` 22 | 23 | // path 24 | Path string `json:"path,omitempty"` 25 | } 26 | 27 | // Validate validates this track endpoint meta 28 | func (m *TrackEndpointMeta) Validate(formats strfmt.Registry) error { 29 | return nil 30 | } 31 | 32 | // ContextValidate validates this track endpoint meta based on context it is used 33 | func (m *TrackEndpointMeta) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 34 | return nil 35 | } 36 | 37 | // MarshalBinary interface implementation 38 | func (m *TrackEndpointMeta) MarshalBinary() ([]byte, error) { 39 | if m == nil { 40 | return nil, nil 41 | } 42 | return swag.WriteJSON(m) 43 | } 44 | 45 | // UnmarshalBinary interface implementation 46 | func (m *TrackEndpointMeta) UnmarshalBinary(b []byte) error { 47 | var res TrackEndpointMeta 48 | if err := swag.ReadJSON(b, &res); err != nil { 49 | return err 50 | } 51 | *m = res 52 | return nil 53 | } 54 | -------------------------------------------------------------------------------- /mservclient/models/response_processor.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // ResponseProcessor response processor 16 | // 17 | // swagger:model ResponseProcessor 18 | type ResponseProcessor struct { 19 | 20 | // name 21 | Name string `json:"name,omitempty"` 22 | 23 | // options 24 | Options interface{} `json:"options,omitempty"` 25 | } 26 | 27 | // Validate validates this response processor 28 | func (m *ResponseProcessor) Validate(formats strfmt.Registry) error { 29 | return nil 30 | } 31 | 32 | // ContextValidate validates this response processor based on context it is used 33 | func (m *ResponseProcessor) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 34 | return nil 35 | } 36 | 37 | // MarshalBinary interface implementation 38 | func (m *ResponseProcessor) MarshalBinary() ([]byte, error) { 39 | if m == nil { 40 | return nil, nil 41 | } 42 | return swag.WriteJSON(m) 43 | } 44 | 45 | // UnmarshalBinary interface implementation 46 | func (m *ResponseProcessor) UnmarshalBinary(b []byte) error { 47 | var res ResponseProcessor 48 | if err := swag.ReadJSON(b, &res); err != nil { 49 | return err 50 | } 51 | *m = res 52 | return nil 53 | } 54 | -------------------------------------------------------------------------------- /mservctl/cmd/push.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "os" 5 | "time" 6 | 7 | "github.com/spf13/cobra" 8 | 9 | "github.com/TykTechnologies/mserv/mservclient/client/mw" 10 | ) 11 | 12 | // pushCmd represents the push command 13 | var pushCmd = &cobra.Command{ 14 | Use: "push", 15 | Short: "Pushes a middleware to mserv", 16 | Long: `Uploads a bundle file created with tyk CLI to mserv`, 17 | Example: `mservctl push /path/to/bundle.zip`, 18 | Args: cobra.ExactArgs(1), 19 | Run: pushMiddleware, 20 | } 21 | 22 | func init() { 23 | rootCmd.AddCommand(pushCmd) 24 | 25 | pushCmd.Flags().BoolP("storeonly", "s", false, "Don't process, just store it") 26 | pushCmd.Flags().StringP("apiid", "a", "", "Optional API ID") 27 | } 28 | 29 | func pushMiddleware(cmd *cobra.Command, args []string) { 30 | file, err := os.Open(args[0]) 31 | if err != nil { 32 | log.WithError(err).Error("Couldn't open the bundle file") 33 | return 34 | } 35 | defer file.Close() 36 | 37 | apiID := cmd.Flag("apiid").Value.String() 38 | storeOnly := cmd.Flag("storeonly").Value.String() == "true" 39 | 40 | params := mw.NewMwAddParams().WithUploadFile(file).WithTimeout(120 * time.Second).WithAPIID(&apiID).WithStoreOnly(&storeOnly) 41 | 42 | resp, err := mservapi.Mw.MwAdd(params, defaultAuth()) 43 | if err != nil { 44 | log.WithError(err).Error("Couldn't push middleware") 45 | return 46 | } 47 | 48 | cmd.Printf("Middleware uploaded successfully, ID: %s\n", resp.GetPayload().Payload.BundleID) 49 | } 50 | -------------------------------------------------------------------------------- /mservclient/models/o_id_provider_config.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // OIDProviderConfig o ID provider config 16 | // 17 | // swagger:model OIDProviderConfig 18 | type OIDProviderConfig struct { 19 | 20 | // client i ds 21 | ClientIDs map[string]string `json:"client_ids,omitempty"` 22 | 23 | // issuer 24 | Issuer string `json:"issuer,omitempty"` 25 | } 26 | 27 | // Validate validates this o ID provider config 28 | func (m *OIDProviderConfig) Validate(formats strfmt.Registry) error { 29 | return nil 30 | } 31 | 32 | // ContextValidate validates this o ID provider config based on context it is used 33 | func (m *OIDProviderConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 34 | return nil 35 | } 36 | 37 | // MarshalBinary interface implementation 38 | func (m *OIDProviderConfig) MarshalBinary() ([]byte, error) { 39 | if m == nil { 40 | return nil, nil 41 | } 42 | return swag.WriteJSON(m) 43 | } 44 | 45 | // UnmarshalBinary interface implementation 46 | func (m *OIDProviderConfig) UnmarshalBinary(b []byte) error { 47 | var res OIDProviderConfig 48 | if err := swag.ReadJSON(b, &res); err != nil { 49 | return err 50 | } 51 | *m = res 52 | return nil 53 | } 54 | -------------------------------------------------------------------------------- /mservclient/models/hard_timeout_meta.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // HardTimeoutMeta hard timeout meta 16 | // 17 | // swagger:model HardTimeoutMeta 18 | type HardTimeoutMeta struct { 19 | 20 | // method 21 | Method string `json:"method,omitempty"` 22 | 23 | // path 24 | Path string `json:"path,omitempty"` 25 | 26 | // time out 27 | TimeOut int64 `json:"timeout,omitempty"` 28 | } 29 | 30 | // Validate validates this hard timeout meta 31 | func (m *HardTimeoutMeta) Validate(formats strfmt.Registry) error { 32 | return nil 33 | } 34 | 35 | // ContextValidate validates this hard timeout meta based on context it is used 36 | func (m *HardTimeoutMeta) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 37 | return nil 38 | } 39 | 40 | // MarshalBinary interface implementation 41 | func (m *HardTimeoutMeta) MarshalBinary() ([]byte, error) { 42 | if m == nil { 43 | return nil, nil 44 | } 45 | return swag.WriteJSON(m) 46 | } 47 | 48 | // UnmarshalBinary interface implementation 49 | func (m *HardTimeoutMeta) UnmarshalBinary(b []byte) error { 50 | var res HardTimeoutMeta 51 | if err := swag.ReadJSON(b, &res); err != nil { 52 | return err 53 | } 54 | *m = res 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /mservclient/models/transform_j_q_meta.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // TransformJQMeta transform j q meta 16 | // 17 | // swagger:model TransformJQMeta 18 | type TransformJQMeta struct { 19 | 20 | // filter 21 | Filter string `json:"filter,omitempty"` 22 | 23 | // method 24 | Method string `json:"method,omitempty"` 25 | 26 | // path 27 | Path string `json:"path,omitempty"` 28 | } 29 | 30 | // Validate validates this transform j q meta 31 | func (m *TransformJQMeta) Validate(formats strfmt.Registry) error { 32 | return nil 33 | } 34 | 35 | // ContextValidate validates this transform j q meta based on context it is used 36 | func (m *TransformJQMeta) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 37 | return nil 38 | } 39 | 40 | // MarshalBinary interface implementation 41 | func (m *TransformJQMeta) MarshalBinary() ([]byte, error) { 42 | if m == nil { 43 | return nil, nil 44 | } 45 | return swag.WriteJSON(m) 46 | } 47 | 48 | // UnmarshalBinary interface implementation 49 | func (m *TransformJQMeta) UnmarshalBinary(b []byte) error { 50 | var res TransformJQMeta 51 | if err := swag.ReadJSON(b, &res); err != nil { 52 | return err 53 | } 54 | *m = res 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /mservclient/models/request_size_meta.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // RequestSizeMeta request size meta 16 | // 17 | // swagger:model RequestSizeMeta 18 | type RequestSizeMeta struct { 19 | 20 | // method 21 | Method string `json:"method,omitempty"` 22 | 23 | // path 24 | Path string `json:"path,omitempty"` 25 | 26 | // size limit 27 | SizeLimit int64 `json:"size_limit,omitempty"` 28 | } 29 | 30 | // Validate validates this request size meta 31 | func (m *RequestSizeMeta) Validate(formats strfmt.Registry) error { 32 | return nil 33 | } 34 | 35 | // ContextValidate validates this request size meta based on context it is used 36 | func (m *RequestSizeMeta) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 37 | return nil 38 | } 39 | 40 | // MarshalBinary interface implementation 41 | func (m *RequestSizeMeta) MarshalBinary() ([]byte, error) { 42 | if m == nil { 43 | return nil, nil 44 | } 45 | return swag.WriteJSON(m) 46 | } 47 | 48 | // UnmarshalBinary interface implementation 49 | func (m *RequestSizeMeta) UnmarshalBinary(b []byte) error { 50 | var res RequestSizeMeta 51 | if err := swag.ReadJSON(b, &res); err != nil { 52 | return err 53 | } 54 | *m = res 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /api/loader.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "fmt" 5 | "github.com/TykTechnologies/mserv/coprocess/bindings/go" 6 | "path" 7 | "plugin" 8 | "reflect" 9 | "runtime" 10 | ) 11 | 12 | var loaded = map[string]bool{} 13 | 14 | func LoadPlugin(funcName, dir, fName string) (func(*coprocess.Object) (*coprocess.Object, error), error) { 15 | _, done := loaded[funcName] 16 | if done { 17 | log.Warning("function symbol already loaded: ", funcName) 18 | return nil, nil 19 | } 20 | 21 | localFname := path.Join(dir, fName) 22 | 23 | defer func() { 24 | if r := recover(); r != nil { 25 | if _, ok := r.(runtime.Error); ok { 26 | log.Error("plugin caused runtime error, ensure it is compiled correctly") 27 | } 28 | log.Error("code panic detected in loader") 29 | } 30 | }() 31 | 32 | // load module 33 | // 1. open the so file to load the symbols 34 | plug, err := plugin.Open(localFname) 35 | if err != nil { 36 | log.Error(err) 37 | } 38 | 39 | // 2. look up a symbol (an exported function or variable) 40 | plFunc, err := plug.Lookup(funcName) 41 | if err != nil { 42 | log.Error() 43 | } 44 | 45 | hFunc, ok := plFunc.(func(*coprocess.Object) (*coprocess.Object, error)) 46 | if !ok { 47 | // try a pointer to func 48 | phFunc, ok := plFunc.(*func(*coprocess.Object) (*coprocess.Object, error)) 49 | if !ok { 50 | return nil, fmt.Errorf("hook is not a HookFunction, is: %v", reflect.TypeOf(plFunc)) 51 | } 52 | hFunc = *phFunc 53 | } 54 | 55 | log.Info("loaded ", funcName) 56 | loaded[funcName] = true 57 | 58 | return hFunc, nil 59 | } 60 | -------------------------------------------------------------------------------- /mservclient/models/method_transform_meta.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // MethodTransformMeta method transform meta 16 | // 17 | // swagger:model MethodTransformMeta 18 | type MethodTransformMeta struct { 19 | 20 | // method 21 | Method string `json:"method,omitempty"` 22 | 23 | // path 24 | Path string `json:"path,omitempty"` 25 | 26 | // to method 27 | ToMethod string `json:"to_method,omitempty"` 28 | } 29 | 30 | // Validate validates this method transform meta 31 | func (m *MethodTransformMeta) Validate(formats strfmt.Registry) error { 32 | return nil 33 | } 34 | 35 | // ContextValidate validates this method transform meta based on context it is used 36 | func (m *MethodTransformMeta) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 37 | return nil 38 | } 39 | 40 | // MarshalBinary interface implementation 41 | func (m *MethodTransformMeta) MarshalBinary() ([]byte, error) { 42 | if m == nil { 43 | return nil, nil 44 | } 45 | return swag.WriteJSON(m) 46 | } 47 | 48 | // UnmarshalBinary interface implementation 49 | func (m *MethodTransformMeta) UnmarshalBinary(b []byte) error { 50 | var res MethodTransformMeta 51 | if err := swag.ReadJSON(b, &res); err != nil { 52 | return err 53 | } 54 | *m = res 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /mservclient/models/return_overrides.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // ReturnOverrides return overrides 16 | // 17 | // swagger:model ReturnOverrides 18 | type ReturnOverrides struct { 19 | 20 | // headers 21 | Headers map[string]string `json:"headers,omitempty"` 22 | 23 | // response code 24 | ResponseCode int32 `json:"response_code,omitempty"` 25 | 26 | // response error 27 | ResponseError string `json:"response_error,omitempty"` 28 | } 29 | 30 | // Validate validates this return overrides 31 | func (m *ReturnOverrides) Validate(formats strfmt.Registry) error { 32 | return nil 33 | } 34 | 35 | // ContextValidate validates this return overrides based on context it is used 36 | func (m *ReturnOverrides) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 37 | return nil 38 | } 39 | 40 | // MarshalBinary interface implementation 41 | func (m *ReturnOverrides) MarshalBinary() ([]byte, error) { 42 | if m == nil { 43 | return nil, nil 44 | } 45 | return swag.WriteJSON(m) 46 | } 47 | 48 | // UnmarshalBinary interface implementation 49 | func (m *ReturnOverrides) UnmarshalBinary(b []byte) error { 50 | var res ReturnOverrides 51 | if err := swag.ReadJSON(b, &res); err != nil { 52 | return err 53 | } 54 | *m = res 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /util/storage/mock/mock.go: -------------------------------------------------------------------------------- 1 | // Package mock provides a store to aid testing of mserv. 2 | package mock 3 | 4 | import ( 5 | "context" 6 | "errors" 7 | 8 | "github.com/TykTechnologies/mserv/storage" 9 | ) 10 | 11 | // ErrEmptyUID is returned when middleware UID is empty. 12 | var ErrEmptyUID = errors.New("UID cannot be empty") 13 | 14 | // Storage is a mock store for testing mserv. 15 | type Storage struct{} 16 | 17 | // GetMWByID is a test mock. 18 | func (s *Storage) GetMWByID(_ context.Context, id string) (*storage.MW, error) { 19 | if id == "" { 20 | return nil, ErrEmptyUID 21 | } 22 | 23 | return &storage.MW{UID: id}, nil 24 | } 25 | 26 | // GetMWByAPIID is a test mock. 27 | func (s *Storage) GetMWByAPIID(_ context.Context, _ string) (*storage.MW, error) { 28 | panic("TODO: Implement") 29 | } 30 | 31 | // GetAllActive is a test mock. 32 | func (s *Storage) GetAllActive(_ context.Context) ([]*storage.MW, error) { 33 | panic("TODO: Implement") 34 | } 35 | 36 | // CreateMW is a test mock. 37 | func (s *Storage) CreateMW(_ context.Context, mw *storage.MW) (string, error) { 38 | if mw.UID == "" { 39 | return "", ErrEmptyUID 40 | } 41 | 42 | return mw.UID, nil 43 | } 44 | 45 | // UpdateMW is a test mock. 46 | func (s *Storage) UpdateMW(_ context.Context, mw *storage.MW) (string, error) { 47 | panic("TODO: Implement") 48 | } 49 | 50 | // DeleteMW is a test mock. 51 | func (s *Storage) DeleteMW(_ context.Context, id string) error { 52 | return nil 53 | } 54 | 55 | // InitMservStore is a test mock. 56 | func (s *Storage) InitMservStore(_ context.Context, tag string) error { 57 | panic("TODO: Implement") 58 | } 59 | -------------------------------------------------------------------------------- /util/storage/storage.go: -------------------------------------------------------------------------------- 1 | package storage 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | 7 | config "github.com/TykTechnologies/mserv/conf" 8 | "github.com/TykTechnologies/mserv/util/logger" 9 | "github.com/TykTechnologies/mserv/util/storage/mongo" 10 | "github.com/TykTechnologies/mserv/util/storage/slave" 11 | ) 12 | 13 | var log = logger.GetLogger("mserv.util.storage") 14 | 15 | type Store interface { 16 | Init() error 17 | SetTag(string) 18 | GetTag() string 19 | Health() map[string]interface{} 20 | Clone() interface{} 21 | } 22 | 23 | var StorageMap = make(map[string]interface{}) 24 | 25 | // GetSpecificStoreType is used to get a sub-type of the Store interface e.g. DashboardStore, 26 | // the storage specific init function must be called by the caller though. 27 | func GetSpecificStoreType(name config.StorageDriver, tag string) (interface{}, error) { 28 | nsTag := fmt.Sprintf("%s:%s", name, tag) 29 | log.Debug("===> Looking up store tag: ", nsTag) 30 | _, ok := StorageMap[nsTag] 31 | if ok { 32 | log.Debugf("store already initialised for tag: %v", nsTag) 33 | return StorageMap[nsTag], nil 34 | } 35 | 36 | switch name { 37 | case "Mongo": 38 | store := &mongo.Store{} 39 | store.SetTag(tag) 40 | 41 | log.Debugf("Mongo store tag is: %v, set to: %v", tag, store.GetTag()) 42 | 43 | // cache 44 | StorageMap[nsTag] = store 45 | 46 | // Set 47 | return store, nil 48 | case "Service": 49 | store, err := slave.NewSlaveClient() 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | // Set 55 | return store, nil 56 | } 57 | 58 | return nil, errors.New("no storage driver set") 59 | } 60 | -------------------------------------------------------------------------------- /mservclient/models/middleware_definition.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // MiddlewareDefinition middleware definition 16 | // 17 | // swagger:model MiddlewareDefinition 18 | type MiddlewareDefinition struct { 19 | 20 | // name 21 | Name string `json:"name,omitempty"` 22 | 23 | // path 24 | Path string `json:"path,omitempty"` 25 | 26 | // raw body only 27 | RawBodyOnly bool `json:"raw_body_only,omitempty"` 28 | 29 | // require session 30 | RequireSession bool `json:"require_session,omitempty"` 31 | } 32 | 33 | // Validate validates this middleware definition 34 | func (m *MiddlewareDefinition) Validate(formats strfmt.Registry) error { 35 | return nil 36 | } 37 | 38 | // ContextValidate validates this middleware definition based on context it is used 39 | func (m *MiddlewareDefinition) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 40 | return nil 41 | } 42 | 43 | // MarshalBinary interface implementation 44 | func (m *MiddlewareDefinition) MarshalBinary() ([]byte, error) { 45 | if m == nil { 46 | return nil, nil 47 | } 48 | return swag.WriteJSON(m) 49 | } 50 | 51 | // UnmarshalBinary interface implementation 52 | func (m *MiddlewareDefinition) UnmarshalBinary(b []byte) error { 53 | var res MiddlewareDefinition 54 | if err := swag.ReadJSON(b, &res); err != nil { 55 | return err 56 | } 57 | *m = res 58 | return nil 59 | } 60 | -------------------------------------------------------------------------------- /mservclient/models/notifications_manager.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // NotificationsManager NotificationsManager handles sending notifications to OAuth endpoints to notify the provider of key changes. 16 | // 17 | // TODO: Make this more generic 18 | // 19 | // swagger:model NotificationsManager 20 | type NotificationsManager struct { 21 | 22 | // o auth key change URL 23 | OAuthKeyChangeURL string `json:"oauth_on_keychange_url,omitempty"` 24 | 25 | // shared secret 26 | SharedSecret string `json:"shared_secret,omitempty"` 27 | } 28 | 29 | // Validate validates this notifications manager 30 | func (m *NotificationsManager) Validate(formats strfmt.Registry) error { 31 | return nil 32 | } 33 | 34 | // ContextValidate validates this notifications manager based on context it is used 35 | func (m *NotificationsManager) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 36 | return nil 37 | } 38 | 39 | // MarshalBinary interface implementation 40 | func (m *NotificationsManager) MarshalBinary() ([]byte, error) { 41 | if m == nil { 42 | return nil, nil 43 | } 44 | return swag.WriteJSON(m) 45 | } 46 | 47 | // UnmarshalBinary interface implementation 48 | func (m *NotificationsManager) UnmarshalBinary(b []byte) error { 49 | var res NotificationsManager 50 | if err := swag.ReadJSON(b, &res); err != nil { 51 | return err 52 | } 53 | *m = res 54 | return nil 55 | } 56 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/BUG.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🐛 Bug report 3 | about: Create a report to help us improve 4 | labels: bug 5 | assignees: # TODO(jlucktay): populate with team(s) once https://github.com/dear-github/dear-github/issues/170 is done 6 | --- 7 | 8 | 9 | 10 | ## Expected Behavior 11 | 12 | 13 | ## Current Behavior 14 | 15 | 16 | ## Possible Solution 17 | 18 | 19 | ## Steps to Reproduce 20 | 21 | 27 | 28 | 1. 29 | 2. 30 | 3. 31 | 32 | ## Screenshots/Video 33 | 34 | 35 | ## Logs/Errors 36 | 37 | 38 | ## Context 39 | 40 | 41 | 42 | ## Your Environment 43 | 44 | 45 | * Browser: 46 | * Name (e.g. Brave, Chrome, Firefox): 47 | * OS (e.g. Linux, macOS, Windows): 48 | * Version: 49 | * Link to environment used: 50 | * Version used: 51 | -------------------------------------------------------------------------------- /mservclient/models/header_injection_meta.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // HeaderInjectionMeta header injection meta 16 | // 17 | // swagger:model HeaderInjectionMeta 18 | type HeaderInjectionMeta struct { 19 | 20 | // act on response 21 | ActOnResponse bool `json:"act_on,omitempty"` 22 | 23 | // add headers 24 | AddHeaders map[string]string `json:"add_headers,omitempty"` 25 | 26 | // delete headers 27 | DeleteHeaders []string `json:"delete_headers"` 28 | 29 | // method 30 | Method string `json:"method,omitempty"` 31 | 32 | // path 33 | Path string `json:"path,omitempty"` 34 | } 35 | 36 | // Validate validates this header injection meta 37 | func (m *HeaderInjectionMeta) Validate(formats strfmt.Registry) error { 38 | return nil 39 | } 40 | 41 | // ContextValidate validates this header injection meta based on context it is used 42 | func (m *HeaderInjectionMeta) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 43 | return nil 44 | } 45 | 46 | // MarshalBinary interface implementation 47 | func (m *HeaderInjectionMeta) MarshalBinary() ([]byte, error) { 48 | if m == nil { 49 | return nil, nil 50 | } 51 | return swag.WriteJSON(m) 52 | } 53 | 54 | // UnmarshalBinary interface implementation 55 | func (m *HeaderInjectionMeta) UnmarshalBinary(b []byte) error { 56 | var res HeaderInjectionMeta 57 | if err := swag.ReadJSON(b, &res); err != nil { 58 | return err 59 | } 60 | *m = res 61 | return nil 62 | } 63 | -------------------------------------------------------------------------------- /mservclient/models/circuit_breaker_meta.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // CircuitBreakerMeta circuit breaker meta 16 | // 17 | // swagger:model CircuitBreakerMeta 18 | type CircuitBreakerMeta struct { 19 | 20 | // method 21 | Method string `json:"method,omitempty"` 22 | 23 | // path 24 | Path string `json:"path,omitempty"` 25 | 26 | // return to service after 27 | ReturnToServiceAfter int64 `json:"return_to_service_after,omitempty"` 28 | 29 | // samples 30 | Samples int64 `json:"samples,omitempty"` 31 | 32 | // threshold percent 33 | ThresholdPercent float64 `json:"threshold_percent,omitempty"` 34 | } 35 | 36 | // Validate validates this circuit breaker meta 37 | func (m *CircuitBreakerMeta) Validate(formats strfmt.Registry) error { 38 | return nil 39 | } 40 | 41 | // ContextValidate validates this circuit breaker meta based on context it is used 42 | func (m *CircuitBreakerMeta) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 43 | return nil 44 | } 45 | 46 | // MarshalBinary interface implementation 47 | func (m *CircuitBreakerMeta) MarshalBinary() ([]byte, error) { 48 | if m == nil { 49 | return nil, nil 50 | } 51 | return swag.WriteJSON(m) 52 | } 53 | 54 | // UnmarshalBinary interface implementation 55 | func (m *CircuitBreakerMeta) UnmarshalBinary(b []byte) error { 56 | var res CircuitBreakerMeta 57 | if err := swag.ReadJSON(b, &res); err != nil { 58 | return err 59 | } 60 | *m = res 61 | return nil 62 | } 63 | -------------------------------------------------------------------------------- /mservclient/models/validate_path_meta.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // ValidatePathMeta validate path meta 16 | // 17 | // swagger:model ValidatePathMeta 18 | type ValidatePathMeta struct { 19 | 20 | // Allows override of default 422 Unprocessible Entity response code for validation errors. 21 | ErrorResponseCode int64 `json:"error_response_code,omitempty"` 22 | 23 | // method 24 | Method string `json:"method,omitempty"` 25 | 26 | // path 27 | Path string `json:"path,omitempty"` 28 | 29 | // schema 30 | Schema interface{} `json:"schema,omitempty"` 31 | 32 | // schema b64 33 | SchemaB64 string `json:"schema_b64,omitempty"` 34 | } 35 | 36 | // Validate validates this validate path meta 37 | func (m *ValidatePathMeta) Validate(formats strfmt.Registry) error { 38 | return nil 39 | } 40 | 41 | // ContextValidate validates this validate path meta based on context it is used 42 | func (m *ValidatePathMeta) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 43 | return nil 44 | } 45 | 46 | // MarshalBinary interface implementation 47 | func (m *ValidatePathMeta) MarshalBinary() ([]byte, error) { 48 | if m == nil { 49 | return nil, nil 50 | } 51 | return swag.WriteJSON(m) 52 | } 53 | 54 | // UnmarshalBinary interface implementation 55 | func (m *ValidatePathMeta) UnmarshalBinary(b []byte) error { 56 | var res ValidatePathMeta 57 | if err := swag.ReadJSON(b, &res); err != nil { 58 | return err 59 | } 60 | *m = res 61 | return nil 62 | } 63 | -------------------------------------------------------------------------------- /mservclient/models/signature_config.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // SignatureConfig signature config 16 | // 17 | // swagger:model SignatureConfig 18 | type SignatureConfig struct { 19 | 20 | // algorithm 21 | Algorithm string `json:"algorithm,omitempty"` 22 | 23 | // allowed clock skew 24 | AllowedClockSkew int64 `json:"allowed_clock_skew,omitempty"` 25 | 26 | // error code 27 | ErrorCode int64 `json:"error_code,omitempty"` 28 | 29 | // error message 30 | ErrorMessage string `json:"error_message,omitempty"` 31 | 32 | // header 33 | Header string `json:"header,omitempty"` 34 | 35 | // secret 36 | Secret string `json:"secret,omitempty"` 37 | } 38 | 39 | // Validate validates this signature config 40 | func (m *SignatureConfig) Validate(formats strfmt.Registry) error { 41 | return nil 42 | } 43 | 44 | // ContextValidate validates this signature config based on context it is used 45 | func (m *SignatureConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 46 | return nil 47 | } 48 | 49 | // MarshalBinary interface implementation 50 | func (m *SignatureConfig) MarshalBinary() ([]byte, error) { 51 | if m == nil { 52 | return nil, nil 53 | } 54 | return swag.WriteJSON(m) 55 | } 56 | 57 | // UnmarshalBinary interface implementation 58 | func (m *SignatureConfig) UnmarshalBinary(b []byte) error { 59 | var res SignatureConfig 60 | if err := swag.ReadJSON(b, &res); err != nil { 61 | return err 62 | } 63 | *m = res 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /mservclient/models/virtual_meta.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // VirtualMeta virtual meta 16 | // 17 | // swagger:model VirtualMeta 18 | type VirtualMeta struct { 19 | 20 | // function source type 21 | FunctionSourceType string `json:"function_source_type,omitempty"` 22 | 23 | // function source URI 24 | FunctionSourceURI string `json:"function_source_uri,omitempty"` 25 | 26 | // method 27 | Method string `json:"method,omitempty"` 28 | 29 | // path 30 | Path string `json:"path,omitempty"` 31 | 32 | // proxy on error 33 | ProxyOnError bool `json:"proxy_on_error,omitempty"` 34 | 35 | // response function name 36 | ResponseFunctionName string `json:"response_function_name,omitempty"` 37 | 38 | // use session 39 | UseSession bool `json:"use_session,omitempty"` 40 | } 41 | 42 | // Validate validates this virtual meta 43 | func (m *VirtualMeta) Validate(formats strfmt.Registry) error { 44 | return nil 45 | } 46 | 47 | // ContextValidate validates this virtual meta based on context it is used 48 | func (m *VirtualMeta) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 49 | return nil 50 | } 51 | 52 | // MarshalBinary interface implementation 53 | func (m *VirtualMeta) MarshalBinary() ([]byte, error) { 54 | if m == nil { 55 | return nil, nil 56 | } 57 | return swag.WriteJSON(m) 58 | } 59 | 60 | // UnmarshalBinary interface implementation 61 | func (m *VirtualMeta) UnmarshalBinary(b []byte) error { 62 | var res VirtualMeta 63 | if err := swag.ReadJSON(b, &res); err != nil { 64 | return err 65 | } 66 | *m = res 67 | return nil 68 | } 69 | -------------------------------------------------------------------------------- /mservclient/models/request_signing_meta.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // RequestSigningMeta request signing meta 16 | // 17 | // swagger:model RequestSigningMeta 18 | type RequestSigningMeta struct { 19 | 20 | // algorithm 21 | Algorithm string `json:"algorithm,omitempty"` 22 | 23 | // certificate Id 24 | CertificateID string `json:"certificate_id,omitempty"` 25 | 26 | // header list 27 | HeaderList []string `json:"header_list"` 28 | 29 | // is enabled 30 | IsEnabled bool `json:"is_enabled,omitempty"` 31 | 32 | // key Id 33 | KeyID string `json:"key_id,omitempty"` 34 | 35 | // secret 36 | Secret string `json:"secret,omitempty"` 37 | 38 | // signature header 39 | SignatureHeader string `json:"signature_header,omitempty"` 40 | } 41 | 42 | // Validate validates this request signing meta 43 | func (m *RequestSigningMeta) Validate(formats strfmt.Registry) error { 44 | return nil 45 | } 46 | 47 | // ContextValidate validates this request signing meta based on context it is used 48 | func (m *RequestSigningMeta) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 49 | return nil 50 | } 51 | 52 | // MarshalBinary interface implementation 53 | func (m *RequestSigningMeta) MarshalBinary() ([]byte, error) { 54 | if m == nil { 55 | return nil, nil 56 | } 57 | return swag.WriteJSON(m) 58 | } 59 | 60 | // UnmarshalBinary interface implementation 61 | func (m *RequestSigningMeta) UnmarshalBinary(b []byte) error { 62 | var res RequestSigningMeta 63 | if err := swag.ReadJSON(b, &res); err != nil { 64 | return err 65 | } 66 | *m = res 67 | return nil 68 | } 69 | -------------------------------------------------------------------------------- /mservclient/models/cache_options.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // CacheOptions cache options 16 | // 17 | // swagger:model CacheOptions 18 | type CacheOptions struct { 19 | 20 | // cache all safe requests 21 | CacheAllSafeRequests bool `json:"cache_all_safe_requests,omitempty"` 22 | 23 | // cache control TTL header 24 | CacheControlTTLHeader string `json:"cache_control_ttl_header,omitempty"` 25 | 26 | // cache only response codes 27 | CacheOnlyResponseCodes []int64 `json:"cache_response_codes"` 28 | 29 | // cache timeout 30 | CacheTimeout int64 `json:"cache_timeout,omitempty"` 31 | 32 | // enable cache 33 | EnableCache bool `json:"enable_cache,omitempty"` 34 | 35 | // enable upstream cache control 36 | EnableUpstreamCacheControl bool `json:"enable_upstream_cache_control,omitempty"` 37 | } 38 | 39 | // Validate validates this cache options 40 | func (m *CacheOptions) Validate(formats strfmt.Registry) error { 41 | return nil 42 | } 43 | 44 | // ContextValidate validates this cache options based on context it is used 45 | func (m *CacheOptions) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 46 | return nil 47 | } 48 | 49 | // MarshalBinary interface implementation 50 | func (m *CacheOptions) MarshalBinary() ([]byte, error) { 51 | if m == nil { 52 | return nil, nil 53 | } 54 | return swag.WriteJSON(m) 55 | } 56 | 57 | // UnmarshalBinary interface implementation 58 | func (m *CacheOptions) UnmarshalBinary(b []byte) error { 59 | var res CacheOptions 60 | if err := swag.ReadJSON(b, &res); err != nil { 61 | return err 62 | } 63 | *m = res 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /mservclient/models/api_limit.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // APILimit APILimit stores quota and rate limit on ACL level (per API) 16 | // 17 | // swagger:model APILimit 18 | type APILimit struct { 19 | 20 | // per 21 | Per float64 `json:"per,omitempty"` 22 | 23 | // quota max 24 | QuotaMax int64 `json:"quota_max,omitempty"` 25 | 26 | // quota remaining 27 | QuotaRemaining int64 `json:"quota_remaining,omitempty"` 28 | 29 | // quota renewal rate 30 | QuotaRenewalRate int64 `json:"quota_renewal_rate,omitempty"` 31 | 32 | // quota renews 33 | QuotaRenews int64 `json:"quota_renews,omitempty"` 34 | 35 | // rate 36 | Rate float64 `json:"rate,omitempty"` 37 | 38 | // throttle interval 39 | ThrottleInterval float64 `json:"throttle_interval,omitempty"` 40 | 41 | // throttle retry limit 42 | ThrottleRetryLimit int64 `json:"throttle_retry_limit,omitempty"` 43 | } 44 | 45 | // Validate validates this API limit 46 | func (m *APILimit) Validate(formats strfmt.Registry) error { 47 | return nil 48 | } 49 | 50 | // ContextValidate validates this API limit based on context it is used 51 | func (m *APILimit) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 52 | return nil 53 | } 54 | 55 | // MarshalBinary interface implementation 56 | func (m *APILimit) MarshalBinary() ([]byte, error) { 57 | if m == nil { 58 | return nil, nil 59 | } 60 | return swag.WriteJSON(m) 61 | } 62 | 63 | // UnmarshalBinary interface implementation 64 | func (m *APILimit) UnmarshalBinary(b []byte) error { 65 | var res APILimit 66 | if err := swag.ReadJSON(b, &res); err != nil { 67 | return err 68 | } 69 | *m = res 70 | return nil 71 | } 72 | -------------------------------------------------------------------------------- /mservctl/cmd/fetch.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | 6 | coprocess "github.com/TykTechnologies/mserv/coprocess/bindings/go" 7 | "github.com/TykTechnologies/mserv/mservclient/client/mw" 8 | "github.com/olekukonko/tablewriter" 9 | "github.com/spf13/cobra" 10 | ) 11 | 12 | // fetchCmd represents the fetch command 13 | var fetchCmd = &cobra.Command{ 14 | Use: "fetch", 15 | Short: "Fetches a middleware record from mserv", 16 | Long: `Fetches a middleware record by ID, e.g.: 17 | 18 | $ mservctl fetch 13b0eb10-419f-40ef-838d-6d26bb2eeaa8`, 19 | Args: cobra.ExactArgs(1), 20 | Run: fetchMiddleware, 21 | } 22 | 23 | func init() { 24 | rootCmd.AddCommand(fetchCmd) 25 | 26 | fetchCmd.Flags().BoolP("functions", "f", false, "Show plugin functions") 27 | } 28 | 29 | func fetchMiddleware(cmd *cobra.Command, args []string) { 30 | params := mw.NewMwFetchParams().WithID(args[0]) 31 | resp, err := mservapi.Mw.MwFetch(params, defaultAuth()) 32 | if err != nil { 33 | log.WithError(err).Error("Couldn't fetch middleware") 34 | return 35 | } 36 | 37 | showFuncs := cmd.Flag("functions").Value.String() == "true" 38 | 39 | headers := []string{"ID", "Active", "Serve Only", "Last Update"} 40 | if showFuncs { 41 | headers = append(headers, "Function", "Type") 42 | } 43 | 44 | table := tablewriter.NewWriter(cmd.OutOrStdout()) 45 | table.SetHeader(headers) 46 | table.SetBorder(false) 47 | table.SetRowLine(false) 48 | table.SetCenterSeparator("") 49 | table.SetAutoMergeCells(false) 50 | table.SetColumnSeparator("") 51 | table.SetRowSeparator("") 52 | table.SetHeaderAlignment(3) 53 | 54 | mw := resp.GetPayload().Payload 55 | 56 | row := []string{ 57 | mw.UID, 58 | fmt.Sprintf("%v", mw.Active), 59 | fmt.Sprintf("%v", mw.DownloadOnly), 60 | mw.Added.String(), 61 | } 62 | table.Append(row) 63 | 64 | if showFuncs { 65 | for _, pl := range mw.Plugins { 66 | plrow := []string{ 67 | "", 68 | "", 69 | "", 70 | "", 71 | pl.Name, 72 | coprocess.HookType(pl.Type).String(), 73 | } 74 | table.Append(plrow) 75 | } 76 | } 77 | 78 | table.Render() 79 | } 80 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Description 4 | 5 | 6 | ## Related Issue 7 | 8 | 9 | 10 | 11 | 12 | ## Motivation and Context 13 | 14 | 15 | ## Test Coverage For This Change 16 | 17 | 18 | 19 | ## Screenshots (if appropriate) 20 | 21 | ## Types of changes 22 | 23 | - [ ] Bug fix (non-breaking change which fixes an issue) 24 | - [ ] New feature (non-breaking change which adds functionality) 25 | - [ ] Breaking change (fix or feature that would cause existing functionality to change) 26 | 27 | ## Checklist 28 | 29 | 30 | - [ ] Make sure you are requesting to **pull a topic/feature/bugfix branch** (right side). If PRing from your fork, don't come from your `master`! 31 | - [ ] Make sure you are making a pull request against our **`master` branch** (left side). Also, it would be best if you started *your change* off *our latest `master`*. 32 | - [ ] My change requires a change to the documentation. 33 | - [ ] If you've changed APIs, describe what needs to be updated in the documentation. 34 | - [ ] I have updated the documentation accordingly. 35 | - [ ] Modules dependencies have been updated; run `go mod tidy` in applicable directories. 36 | - [ ] I have added tests to cover my changes. 37 | - [ ] All new and existing tests passed. 38 | - [ ] Check your code additions will not fail linting checks: 39 | - [ ] `gofmt -s -w .` 40 | - [ ] `golangci-lint run` 41 | -------------------------------------------------------------------------------- /mservclient/models/service_discovery_configuration.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/strfmt" 12 | "github.com/go-openapi/swag" 13 | ) 14 | 15 | // ServiceDiscoveryConfiguration service discovery configuration 16 | // 17 | // swagger:model ServiceDiscoveryConfiguration 18 | type ServiceDiscoveryConfiguration struct { 19 | 20 | // cache timeout 21 | CacheTimeout int64 `json:"cache_timeout,omitempty"` 22 | 23 | // data path 24 | DataPath string `json:"data_path,omitempty"` 25 | 26 | // endpoint returns list 27 | EndpointReturnsList bool `json:"endpoint_returns_list,omitempty"` 28 | 29 | // parent data path 30 | ParentDataPath string `json:"parent_data_path,omitempty"` 31 | 32 | // port data path 33 | PortDataPath string `json:"port_data_path,omitempty"` 34 | 35 | // query endpoint 36 | QueryEndpoint string `json:"query_endpoint,omitempty"` 37 | 38 | // target path 39 | TargetPath string `json:"target_path,omitempty"` 40 | 41 | // use discovery service 42 | UseDiscoveryService bool `json:"use_discovery_service,omitempty"` 43 | 44 | // use nested query 45 | UseNestedQuery bool `json:"use_nested_query,omitempty"` 46 | 47 | // use target list 48 | UseTargetList bool `json:"use_target_list,omitempty"` 49 | } 50 | 51 | // Validate validates this service discovery configuration 52 | func (m *ServiceDiscoveryConfiguration) Validate(formats strfmt.Registry) error { 53 | return nil 54 | } 55 | 56 | // ContextValidate validates this service discovery configuration based on context it is used 57 | func (m *ServiceDiscoveryConfiguration) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 58 | return nil 59 | } 60 | 61 | // MarshalBinary interface implementation 62 | func (m *ServiceDiscoveryConfiguration) MarshalBinary() ([]byte, error) { 63 | if m == nil { 64 | return nil, nil 65 | } 66 | return swag.WriteJSON(m) 67 | } 68 | 69 | // UnmarshalBinary interface implementation 70 | func (m *ServiceDiscoveryConfiguration) UnmarshalBinary(b []byte) error { 71 | var res ServiceDiscoveryConfiguration 72 | if err := swag.ReadJSON(b, &res); err != nil { 73 | return err 74 | } 75 | *m = res 76 | return nil 77 | } 78 | -------------------------------------------------------------------------------- /integration/integration.yaml: -------------------------------------------------------------------------------- 1 | name: Integration tests for mserv and mservctl 2 | 3 | testcases: 4 | - name: List 5 | steps: 6 | - script: ../bin/mservctl list -e http://localhost:8989 7 | assertions: 8 | - result.code ShouldEqual 0 9 | - result.systemout MustContainSubstring "ID ACTIVE SERVE ONLY LAST UPDATE" 10 | - result.systemout MustNotContainSubstring true # Should not have any other rows as header row. 11 | - result.systemout MustNotContainSubstring false # Should not have any other rows as header row. 12 | 13 | - name: Push 14 | steps: 15 | - script: ../bin/mservctl push -e http://localhost:8989 ../bundles/simple/bundle.zip 16 | assertions: 17 | - result.code ShouldEqual 0 18 | - result.systemerr MustContainSubstring Middleware uploaded successfully, ID 19 | vars: 20 | bundle: 21 | from: result.systemerr 22 | regex: "Middleware uploaded successfully, ID: ([a-z0-9-]+)" 23 | 24 | - name: Fetch 25 | steps: 26 | - script: ../bin/mservctl fetch -e http://localhost:8989 {{.Push.bundle}} 27 | assertions: 28 | - result.code ShouldEqual 0 29 | - result.systemout MustContainSubstring {{.Push.bundle}} 30 | 31 | - name: Update 32 | steps: 33 | - script: ../bin/mservctl update -e http://localhost:8989 {{.Push.bundle}} ../bundles/simple/bundle.zip 34 | assertions: 35 | - result.code ShouldEqual 0 36 | - result.systemerr MustContainSubstring Middleware uploaded successfully, ID 37 | vars: 38 | bundle: 39 | from: result.systemerr 40 | regex: "Middleware uploaded successfully, ID: ([a-z0-9-]+)" 41 | 42 | - name: Delete 43 | steps: 44 | - script: ../bin/mservctl delete -e http://localhost:8989 {{.Push.bundle}} 45 | assertions: 46 | - result.code ShouldEqual 0 47 | - result.systemerr MustContainSubstring "Middleware deleted successfully, ID" 48 | 49 | - name: List 50 | steps: 51 | - script: ../bin/mservctl list -e http://localhost:8989 52 | assertions: 53 | - result.code ShouldEqual 0 54 | - result.systemout MustContainSubstring "ID ACTIVE SERVE ONLY LAST UPDATE" 55 | - result.systemout MustNotContainSubstring true # Should not have any other rows as header row. 56 | - result.systemout MustNotContainSubstring false # Should not have any other rows as header row. 57 | -------------------------------------------------------------------------------- /mservctl/cmd/list.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | 6 | coprocess "github.com/TykTechnologies/mserv/coprocess/bindings/go" 7 | "github.com/TykTechnologies/mserv/mservclient/client/mw" 8 | "github.com/olekukonko/tablewriter" 9 | "github.com/spf13/cobra" 10 | ) 11 | 12 | // listCmd represents the list command 13 | var listCmd = &cobra.Command{ 14 | Use: "list", 15 | Short: "List middleware in mserv", 16 | Long: `Lists middleware known to mserv. By default everything is listed, use filters to limit output.`, 17 | Run: listMiddleware, 18 | } 19 | 20 | func init() { 21 | rootCmd.AddCommand(listCmd) 22 | 23 | listCmd.Flags().BoolP("functions", "f", false, "Show plugin functions") 24 | listCmd.Flags().BoolP("downloadonly", "d", false, "Show only download middleware") 25 | listCmd.Flags().BoolP("pluginsonly", "p", false, "Show only plugin middleware") 26 | } 27 | 28 | func listMiddleware(cmd *cobra.Command, args []string) { 29 | resp, err := mservapi.Mw.MwListAll(mw.NewMwListAllParams(), defaultAuth()) 30 | if err != nil { 31 | log.WithError(err).Error("Couldn't fetch middleware") 32 | return 33 | } 34 | 35 | showFuncs := cmd.Flag("functions").Value.String() == "true" 36 | downloadOnly := cmd.Flag("downloadonly").Value.String() == "true" 37 | pluginsOnly := cmd.Flag("pluginsonly").Value.String() == "true" 38 | 39 | headers := []string{"ID", "Active", "Serve Only", "Last Update"} 40 | if showFuncs { 41 | headers = append(headers, "Function", "Type") 42 | } 43 | 44 | table := tablewriter.NewWriter(cmd.OutOrStdout()) 45 | table.SetHeader(headers) 46 | table.SetBorder(false) 47 | table.SetRowLine(false) 48 | table.SetCenterSeparator("") 49 | table.SetAutoMergeCells(false) 50 | table.SetColumnSeparator("") 51 | table.SetRowSeparator("") 52 | table.SetHeaderAlignment(3) 53 | 54 | mws := resp.GetPayload().Payload 55 | for _, mw := range mws { 56 | if downloadOnly && !mw.DownloadOnly { 57 | continue 58 | } 59 | if pluginsOnly && mw.DownloadOnly { 60 | continue 61 | } 62 | 63 | row := []string{ 64 | mw.UID, 65 | fmt.Sprintf("%v", mw.Active), 66 | fmt.Sprintf("%v", mw.DownloadOnly), 67 | mw.Added.String(), 68 | } 69 | table.Append(row) 70 | 71 | if showFuncs { 72 | for _, pl := range mw.Plugins { 73 | plrow := []string{ 74 | "", 75 | "", 76 | "", 77 | "", 78 | pl.Name, 79 | coprocess.HookType(pl.Type).String(), 80 | } 81 | table.Append(plrow) 82 | } 83 | } 84 | } 85 | table.Render() 86 | } 87 | -------------------------------------------------------------------------------- /http_funcs/api_handlers_add_test.go: -------------------------------------------------------------------------------- 1 | package http_funcs_test 2 | 3 | import ( 4 | "io/ioutil" 5 | "net/http" 6 | "net/http/httptest" 7 | "path/filepath" 8 | "testing" 9 | 10 | "github.com/matryer/is" 11 | 12 | config "github.com/TykTechnologies/mserv/conf" 13 | ) 14 | 15 | func TestAddMWStoreBundleOnly(t *testing.T) { 16 | is := is.New(t) 17 | srv := setupServerAndTempDir(t) 18 | 19 | for name, tc := range addMWTestCases { 20 | name, tc := name, tc 21 | t.Run(name, func(t *testing.T) { 22 | req := prepareAddRequest(t, tc.testBodyBytes) 23 | req.Form.Add("store_only", "true") // target the 'StoreBundleOnly' code path 24 | 25 | // Handle the request 26 | w := httptest.NewRecorder() 27 | srv.AddMW(w, req) 28 | 29 | // Parse the response 30 | resp := w.Result() 31 | defer is.NoErr(resp.Body.Close()) // could not close response body cleanly 32 | 33 | is.Equal(tc.expectedStatus, resp.StatusCode) // expected response status does not equal actual 34 | 35 | bod, errRead := ioutil.ReadAll(resp.Body) 36 | is.NoErr(errRead) // could not read response body 37 | t.Logf("response: %s %s", resp.Status, bod) 38 | }) 39 | } 40 | } 41 | 42 | func TestAddMWHandleNewBundle(t *testing.T) { 43 | is := is.New(t) 44 | srv := setupServerAndTempDir(t) 45 | 46 | t.Run("Compressed (ZIP) upload is OK", func(t *testing.T) { 47 | fileCountPath := filepath.Join(config.GetConf().Mserv.MiddlewarePath, "plugins") 48 | startCount, err := ioutil.ReadDir(fileCountPath) 49 | is.NoErr(err) // could not read 'config.Mserv.MiddlewarePath+"/plugins"' directory 50 | 51 | req := prepareAddRequest(t, compressedTestData) 52 | req.Form.Add("store_only", "false") // target the 'HandleNewBundle' code path 53 | 54 | // Handle the request 55 | w := httptest.NewRecorder() 56 | srv.AddMW(w, req) 57 | 58 | // Parse the response 59 | resp := w.Result() 60 | defer is.NoErr(resp.Body.Close()) // could not close response body cleanly 61 | 62 | is.Equal(http.StatusOK, resp.StatusCode) // expected response status does not equal actual 63 | 64 | bod, errRead := ioutil.ReadAll(resp.Body) 65 | is.NoErr(errRead) // could not read response body 66 | t.Logf("response: %s %s", resp.Status, bod) 67 | 68 | finishCount, err := ioutil.ReadDir(fileCountPath) 69 | is.NoErr(err) // could not read 'config.Mserv.MiddlewarePath+"/plugins"' directory 70 | is.Equal(len(startCount), len(finishCount)) // should not leave uploads behind unless configured to do so 71 | }) 72 | } 73 | -------------------------------------------------------------------------------- /util/storage/mongo/mongo.go: -------------------------------------------------------------------------------- 1 | package mongo 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | 8 | "github.com/patrickmn/go-cache" 9 | "go.mongodb.org/mongo-driver/mongo" 10 | "go.mongodb.org/mongo-driver/mongo/options" 11 | "go.mongodb.org/mongo-driver/mongo/readpref" 12 | "go.mongodb.org/mongo-driver/x/mongo/driver/connstring" 13 | 14 | "github.com/TykTechnologies/mserv/util/logger" 15 | ) 16 | 17 | const ( 18 | mservCol = "mserv" 19 | ) 20 | 21 | type Store struct { 22 | db *mongo.Database 23 | conf *MgoStoreConf 24 | objCache *cache.Cache 25 | tag string 26 | initialised bool 27 | } 28 | 29 | var log = logger.GetLogger("mserv.util.storage.mgo") 30 | 31 | func getAvailableTagsForErr() string { 32 | tags := "" 33 | for t := range GetConf().MongoStore { 34 | tags = " " + t 35 | } 36 | 37 | return tags 38 | } 39 | 40 | func (m *Store) Init() error { 41 | if m.initialised { 42 | return nil 43 | } 44 | 45 | c, ok := GetConf().MongoStore[m.tag] 46 | if !ok { 47 | return fmt.Errorf("no matching store config tag found for tag: %v (available:%v)", m.tag, getAvailableTagsForErr()) 48 | } 49 | 50 | m.conf = c 51 | log.Info("initialising mgo store") 52 | 53 | cs, err := connstring.ParseAndValidate(m.conf.ConnStr) 54 | if err != nil { 55 | return fmt.Errorf("error validating mongo connection string: %w", err) 56 | } 57 | 58 | opts := options.Client(). 59 | ApplyURI(m.conf.ConnStr) 60 | 61 | if err := opts.Validate(); err != nil { 62 | return fmt.Errorf("error validating mongodb settings: %w", err) 63 | } 64 | 65 | // Connect to MongoDB. 66 | mgo, err := mongo.Connect(context.Background(), opts) 67 | if err != nil { 68 | return fmt.Errorf("error connectiong to mongodb: %w", err) 69 | } 70 | 71 | // Verify that we have active DB connection. 72 | if err := mgo.Ping(context.Background(), readpref.Primary()); err != nil { 73 | return fmt.Errorf("error pinging mongodb: %w", err) 74 | } 75 | 76 | // Connect to default database. 77 | m.db = mgo.Database(cs.Database) 78 | 79 | log.Info("Initialising cache") 80 | m.objCache = cache.New(1*time.Minute, 5*time.Minute) 81 | 82 | m.initialised = true 83 | 84 | return nil 85 | } 86 | 87 | func (m *Store) GetTag() string { 88 | return m.tag 89 | } 90 | 91 | func (m *Store) Health() map[string]interface{} { 92 | return map[string]interface{}{ 93 | "ok": m.initialised, 94 | } 95 | } 96 | 97 | func (m *Store) SetTag(tag string) { 98 | m.tag = tag 99 | } 100 | -------------------------------------------------------------------------------- /mservclient/client/system/system_client.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package system 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "fmt" 10 | 11 | "github.com/go-openapi/runtime" 12 | "github.com/go-openapi/strfmt" 13 | ) 14 | 15 | // New creates a new system API client. 16 | func New(transport runtime.ClientTransport, formats strfmt.Registry) ClientService { 17 | return &Client{transport: transport, formats: formats} 18 | } 19 | 20 | /* 21 | Client for system API 22 | */ 23 | type Client struct { 24 | transport runtime.ClientTransport 25 | formats strfmt.Registry 26 | } 27 | 28 | // ClientOption is the option for Client methods 29 | type ClientOption func(*runtime.ClientOperation) 30 | 31 | // ClientService is the interface for Client methods 32 | type ClientService interface { 33 | Health(params *HealthParams, opts ...ClientOption) (*HealthOK, error) 34 | 35 | SetTransport(transport runtime.ClientTransport) 36 | } 37 | 38 | /* 39 | Health queries health status of mserv service 40 | */ 41 | func (a *Client) Health(params *HealthParams, opts ...ClientOption) (*HealthOK, error) { 42 | // TODO: Validate the params before sending 43 | if params == nil { 44 | params = NewHealthParams() 45 | } 46 | op := &runtime.ClientOperation{ 47 | ID: "health", 48 | Method: "GET", 49 | PathPattern: "/health", 50 | ProducesMediaTypes: []string{"application/json"}, 51 | ConsumesMediaTypes: []string{"application/json"}, 52 | Schemes: []string{"http", "https"}, 53 | Params: params, 54 | Reader: &HealthReader{formats: a.formats}, 55 | Context: params.Context, 56 | Client: params.HTTPClient, 57 | } 58 | for _, opt := range opts { 59 | opt(op) 60 | } 61 | 62 | result, err := a.transport.Submit(op) 63 | if err != nil { 64 | return nil, err 65 | } 66 | success, ok := result.(*HealthOK) 67 | if ok { 68 | return success, nil 69 | } 70 | // unexpected success response 71 | // safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue 72 | msg := fmt.Sprintf("unexpected success response for health: API contract not enforced by server. Client expected to get an error, but got: %T", result) 73 | panic(msg) 74 | } 75 | 76 | // SetTransport changes the transport on the client 77 | func (a *Client) SetTransport(transport runtime.ClientTransport) { 78 | a.transport = transport 79 | } 80 | -------------------------------------------------------------------------------- /util/conf/config.go: -------------------------------------------------------------------------------- 1 | // Package conf provides primitives for pulling configuration data for 2 | // individual modules in the controller - modules should use this package 3 | // to retrieve module-specific configuration 4 | package conf 5 | 6 | import ( 7 | "encoding/json" 8 | "io/ioutil" 9 | "os" 10 | 11 | "github.com/sirupsen/logrus" 12 | ) 13 | 14 | type BaseConfig struct{} 15 | 16 | var ( 17 | log = logrus.New().WithField("app", "mserv.util.conf") // need to use independent logger 18 | confDat = make([]byte, 0) 19 | ) 20 | 21 | // GlobalConf is the config that the main application provides, each module 22 | // actually gets it's own config objects that are locally defined. 23 | type GlobalConf struct{} 24 | 25 | var gConf *GlobalConf 26 | 27 | // Flush will reinitialise/forget any config data already read. 28 | func Flush() { 29 | confDat = make([]byte, 0) 30 | 31 | log.Debug("flushed config bytes") 32 | } 33 | 34 | // ReadConf provides the raw data from the config file. 35 | // The config file's location can be set via an environment variable `TYK_MSERV_CONFIG`, and if not specified defaults 36 | // to `/etc/tyk-mserv/config.json`. 37 | // A module can use this function to then parse the raw config data into it's own module-specific config type. 38 | func ReadConf() []byte { 39 | if len(confDat) > 0 { 40 | return confDat 41 | } 42 | 43 | confFile := os.Getenv("TYK_MSERV_CONFIG") 44 | if confFile == "" { 45 | confFile = "/etc/tyk-mserv/config.json" 46 | } 47 | 48 | // Add/replace file path field on package-level logger 49 | log = log.WithField("file", confFile) 50 | log.Debug("config file path") 51 | 52 | if _, err := os.Stat(confFile); err != nil { 53 | if os.IsNotExist(err) { 54 | log.Warning("config file does not exist") 55 | 56 | confDat = []byte("{}") 57 | 58 | return confDat 59 | } 60 | 61 | log.WithError(err).Warning("could not stat config file") 62 | } 63 | 64 | dat, err := ioutil.ReadFile(confFile) //nolint:gosec // User allowed to set config file path via env var 65 | if err != nil { 66 | log.WithError(err).Fatal("could not read config file") 67 | } 68 | 69 | log.Debugf("config file is %d bytes", len(dat)) 70 | 71 | confDat = dat 72 | 73 | return confDat 74 | } 75 | 76 | // GetGlobalConf provides the global config object that can be accessed from all modules where necessary. 77 | func GetGlobalConf() *GlobalConf { 78 | if gConf != nil { 79 | return gConf 80 | } 81 | 82 | gConf = &GlobalConf{} 83 | 84 | if err := json.Unmarshal(ReadConf(), gConf); err != nil { 85 | log.WithError(err).Fatal("could not unmarshal driver config") 86 | } 87 | 88 | return gConf 89 | } 90 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # Create a draft release and attach mservctl binaries 2 | 3 | name: Draft release 4 | 5 | on: 6 | push: 7 | tags: 8 | - "v*" 9 | 10 | env: 11 | BINARY_NAME: mservctl 12 | 13 | jobs: 14 | build: 15 | name: Build the 'mservctl' CLI binary 16 | 17 | strategy: 18 | matrix: 19 | platform: [ubuntu-latest, macos-latest] 20 | arch: [amd64] 21 | 22 | runs-on: ${{ matrix.platform }} 23 | 24 | steps: 25 | - name: checkout ${{ github.repository }} 26 | uses: actions/checkout@v4 27 | with: 28 | fetch-depth: 0 29 | 30 | - uses: actions/setup-go@v5 31 | with: 32 | go-version: "1.22" 33 | 34 | - name: Build the CLI binary 35 | run: | 36 | cd mservctl 37 | CGO_ENABLED=0 go build -o ../bin/mservctl 38 | cd .. 39 | 40 | - name: Upload ${{ runner.os }} ${{ matrix.arch }} binary 41 | uses: actions/upload-artifact@v4 42 | with: 43 | name: mservctl.${{ runner.os }}.${{ matrix.arch }} 44 | path: bin/mservctl 45 | 46 | release: 47 | needs: [build] 48 | 49 | name: Create a draft release, and attach the built binaries 50 | 51 | runs-on: ubuntu-latest 52 | 53 | steps: 54 | - uses: actions/create-release@v1 55 | id: draft-release 56 | env: 57 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 58 | with: 59 | tag_name: ${{ github.ref }} 60 | release_name: Release ${{ github.ref }} 61 | draft: true 62 | 63 | - uses: actions/download-artifact@v4 64 | with: 65 | name: mservctl.Linux.amd64 66 | path: mservctl.Linux.amd64 67 | 68 | - name: Attach Linux binary 69 | uses: actions/upload-release-asset@v1 70 | env: 71 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 72 | with: 73 | upload_url: ${{ steps.draft-release.outputs.upload_url }} 74 | asset_name: mservctl.Linux.amd64 75 | asset_path: mservctl.Linux.amd64/mservctl 76 | asset_content_type: application/octet-stream 77 | 78 | - uses: actions/download-artifact@v4 79 | with: 80 | name: mservctl.macOS.amd64 81 | path: mservctl.macOS.amd64 82 | 83 | - name: Attach macOS binary 84 | uses: actions/upload-release-asset@v1 85 | env: 86 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 87 | with: 88 | upload_url: ${{ steps.draft-release.outputs.upload_url }} 89 | asset_name: mservctl.macOS.amd64 90 | asset_path: mservctl.macOS.amd64/mservctl 91 | asset_content_type: application/octet-stream 92 | -------------------------------------------------------------------------------- /mservclient/client/invocation/invocation_client.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package invocation 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "fmt" 10 | 11 | "github.com/go-openapi/runtime" 12 | "github.com/go-openapi/strfmt" 13 | ) 14 | 15 | // New creates a new invocation API client. 16 | func New(transport runtime.ClientTransport, formats strfmt.Registry) ClientService { 17 | return &Client{transport: transport, formats: formats} 18 | } 19 | 20 | /* 21 | Client for invocation API 22 | */ 23 | type Client struct { 24 | transport runtime.ClientTransport 25 | formats strfmt.Registry 26 | } 27 | 28 | // ClientOption is the option for Client methods 29 | type ClientOption func(*runtime.ClientOperation) 30 | 31 | // ClientService is the interface for Client methods 32 | type ClientService interface { 33 | Invoke(params *InvokeParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*InvokeOK, error) 34 | 35 | SetTransport(transport runtime.ClientTransport) 36 | } 37 | 38 | /* 39 | Invoke invokes a middleware by name 40 | 41 | Expects a coprocess.Object encoded as JSON in the request body and returns the result in the same way. 42 | */ 43 | func (a *Client) Invoke(params *InvokeParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*InvokeOK, error) { 44 | // TODO: Validate the params before sending 45 | if params == nil { 46 | params = NewInvokeParams() 47 | } 48 | op := &runtime.ClientOperation{ 49 | ID: "invoke", 50 | Method: "POST", 51 | PathPattern: "/execute/{name}", 52 | ProducesMediaTypes: []string{"application/json"}, 53 | ConsumesMediaTypes: []string{"application/json"}, 54 | Schemes: []string{"http", "https"}, 55 | Params: params, 56 | Reader: &InvokeReader{formats: a.formats}, 57 | AuthInfo: authInfo, 58 | Context: params.Context, 59 | Client: params.HTTPClient, 60 | } 61 | for _, opt := range opts { 62 | opt(op) 63 | } 64 | 65 | result, err := a.transport.Submit(op) 66 | if err != nil { 67 | return nil, err 68 | } 69 | success, ok := result.(*InvokeOK) 70 | if ok { 71 | return success, nil 72 | } 73 | // unexpected success response 74 | // safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue 75 | msg := fmt.Sprintf("unexpected success response for invoke: API contract not enforced by server. Client expected to get an error, but got: %T", result) 76 | panic(msg) 77 | } 78 | 79 | // SetTransport changes the transport on the client 80 | func (a *Client) SetTransport(transport runtime.ClientTransport) { 81 | a.transport = transport 82 | } 83 | -------------------------------------------------------------------------------- /mservclient/models/plugin.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/errors" 12 | "github.com/go-openapi/strfmt" 13 | "github.com/go-openapi/swag" 14 | ) 15 | 16 | // Plugin plugin 17 | // 18 | // swagger:model Plugin 19 | type Plugin struct { 20 | 21 | // file name 22 | FileName string `json:"FileName,omitempty"` 23 | 24 | // file ref 25 | FileRef string `json:"FileRef,omitempty"` 26 | 27 | // name 28 | Name string `json:"Name,omitempty"` 29 | 30 | // type 31 | Type HookType `json:"Type,omitempty"` 32 | 33 | // UID 34 | UID string `json:"UID,omitempty"` 35 | } 36 | 37 | // Validate validates this plugin 38 | func (m *Plugin) Validate(formats strfmt.Registry) error { 39 | var res []error 40 | 41 | if err := m.validateType(formats); err != nil { 42 | res = append(res, err) 43 | } 44 | 45 | if len(res) > 0 { 46 | return errors.CompositeValidationError(res...) 47 | } 48 | return nil 49 | } 50 | 51 | func (m *Plugin) validateType(formats strfmt.Registry) error { 52 | if swag.IsZero(m.Type) { // not required 53 | return nil 54 | } 55 | 56 | if err := m.Type.Validate(formats); err != nil { 57 | if ve, ok := err.(*errors.Validation); ok { 58 | return ve.ValidateName("Type") 59 | } else if ce, ok := err.(*errors.CompositeError); ok { 60 | return ce.ValidateName("Type") 61 | } 62 | return err 63 | } 64 | 65 | return nil 66 | } 67 | 68 | // ContextValidate validate this plugin based on the context it is used 69 | func (m *Plugin) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 70 | var res []error 71 | 72 | if err := m.contextValidateType(ctx, formats); err != nil { 73 | res = append(res, err) 74 | } 75 | 76 | if len(res) > 0 { 77 | return errors.CompositeValidationError(res...) 78 | } 79 | return nil 80 | } 81 | 82 | func (m *Plugin) contextValidateType(ctx context.Context, formats strfmt.Registry) error { 83 | 84 | if swag.IsZero(m.Type) { // not required 85 | return nil 86 | } 87 | 88 | if err := m.Type.ContextValidate(ctx, formats); err != nil { 89 | if ve, ok := err.(*errors.Validation); ok { 90 | return ve.ValidateName("Type") 91 | } else if ce, ok := err.(*errors.CompositeError); ok { 92 | return ce.ValidateName("Type") 93 | } 94 | return err 95 | } 96 | 97 | return nil 98 | } 99 | 100 | // MarshalBinary interface implementation 101 | func (m *Plugin) MarshalBinary() ([]byte, error) { 102 | if m == nil { 103 | return nil, nil 104 | } 105 | return swag.WriteJSON(m) 106 | } 107 | 108 | // UnmarshalBinary interface implementation 109 | func (m *Plugin) UnmarshalBinary(b []byte) error { 110 | var res Plugin 111 | if err := swag.ReadJSON(b, &res); err != nil { 112 | return err 113 | } 114 | *m = res 115 | return nil 116 | } 117 | -------------------------------------------------------------------------------- /.golangci.yaml: -------------------------------------------------------------------------------- 1 | issues: 2 | exclude-use-default: false 3 | exclude: 4 | - ^exported var `Err[A-Za-z]+` should have comment or be unexported$ 5 | - ^should have a package comment, unless it's in another file for this package$ 6 | max-issues-per-linter: 0 7 | max-same-issues: 0 8 | new-from-rev: origin/master 9 | 10 | # Excluding configuration per-path, per-linter, per-text and per-source 11 | exclude-rules: 12 | # Exclude some linters from running on test files. 13 | - path: _test\.go 14 | linters: 15 | - dupl 16 | 17 | linters-settings: 18 | dogsled: 19 | max-blank-identifiers: 2 20 | 21 | dupl: 22 | threshold: 50 23 | 24 | errcheck: 25 | check-type-assertions: true 26 | check-blank: true 27 | 28 | errorlint: 29 | errorf: true 30 | 31 | gci: 32 | local-prefixes: github.com/TykTechnologies/mserv 33 | 34 | goconst: 35 | min-len: 3 36 | min-occurrences: 3 37 | 38 | godot: 39 | capital: true 40 | scope: toplevel 41 | 42 | gofmt: 43 | simplify: true 44 | 45 | gofumpt: 46 | extra-rules: true 47 | 48 | govet: 49 | enable-all: true 50 | disable: 51 | - fieldalignment 52 | - shadow 53 | 54 | lll: 55 | line-length: 120 56 | tab-width: 2 57 | 58 | nakedret: 59 | max-func-lines: 25 60 | 61 | nestif: 62 | min-complexity: 4 63 | 64 | nolintlint: 65 | # Exclude following linters from requiring an explanation. Default is []. 66 | allow-no-explanation: [] 67 | 68 | allow-unused: false 69 | allow-leading-space: false 70 | require-explanation: true 71 | require-specific: true 72 | 73 | unparam: 74 | check-exported: true 75 | 76 | whitespace: 77 | multi-if: false 78 | multi-func: false 79 | 80 | wsl: 81 | strict-append: true 82 | allow-assign-and-call: true 83 | allow-multiline-assign: true 84 | allow-cuddle-declarations: false 85 | allow-trailing-comment: false 86 | force-case-trailing-whitespace: 0 87 | force-err-cuddling: true 88 | allow-separated-leading-comment: false 89 | 90 | linters: 91 | enable: 92 | - asciicheck 93 | - bodyclose 94 | - dogsled 95 | - dupl 96 | - errcheck 97 | - errorlint 98 | - gci 99 | - goconst 100 | - gocritic 101 | - godot 102 | - godox 103 | - goerr113 104 | - gofmt 105 | - gofumpt 106 | - gosec 107 | - gosimple 108 | - govet 109 | - ineffassign 110 | - lll 111 | - nakedret 112 | - nestif 113 | - nlreturn 114 | - noctx 115 | - nolintlint 116 | - staticcheck 117 | - stylecheck 118 | - typecheck 119 | - unconvert 120 | - unparam 121 | - unused 122 | - whitespace 123 | - wrapcheck 124 | - wsl 125 | 126 | output: 127 | format: tab 128 | print-issued-lines: true 129 | print-linter-name: true 130 | uniq-by-line: true 131 | sort-results: true 132 | 133 | run: 134 | modules-download-mode: readonly 135 | timeout: 1m 136 | -------------------------------------------------------------------------------- /mservclient/models/file_header.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/errors" 12 | "github.com/go-openapi/strfmt" 13 | "github.com/go-openapi/swag" 14 | ) 15 | 16 | // FileHeader A FileHeader describes a file part of a multipart request. 17 | // 18 | // swagger:model FileHeader 19 | type FileHeader struct { 20 | 21 | // filename 22 | Filename string `json:"Filename,omitempty"` 23 | 24 | // header 25 | Header MIMEHeader `json:"Header,omitempty"` 26 | 27 | // size 28 | Size int64 `json:"Size,omitempty"` 29 | } 30 | 31 | // Validate validates this file header 32 | func (m *FileHeader) Validate(formats strfmt.Registry) error { 33 | var res []error 34 | 35 | if err := m.validateHeader(formats); err != nil { 36 | res = append(res, err) 37 | } 38 | 39 | if len(res) > 0 { 40 | return errors.CompositeValidationError(res...) 41 | } 42 | return nil 43 | } 44 | 45 | func (m *FileHeader) validateHeader(formats strfmt.Registry) error { 46 | if swag.IsZero(m.Header) { // not required 47 | return nil 48 | } 49 | 50 | if m.Header != nil { 51 | if err := m.Header.Validate(formats); err != nil { 52 | if ve, ok := err.(*errors.Validation); ok { 53 | return ve.ValidateName("Header") 54 | } else if ce, ok := err.(*errors.CompositeError); ok { 55 | return ce.ValidateName("Header") 56 | } 57 | return err 58 | } 59 | } 60 | 61 | return nil 62 | } 63 | 64 | // ContextValidate validate this file header based on the context it is used 65 | func (m *FileHeader) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 66 | var res []error 67 | 68 | if err := m.contextValidateHeader(ctx, formats); err != nil { 69 | res = append(res, err) 70 | } 71 | 72 | if len(res) > 0 { 73 | return errors.CompositeValidationError(res...) 74 | } 75 | return nil 76 | } 77 | 78 | func (m *FileHeader) contextValidateHeader(ctx context.Context, formats strfmt.Registry) error { 79 | 80 | if swag.IsZero(m.Header) { // not required 81 | return nil 82 | } 83 | 84 | if err := m.Header.ContextValidate(ctx, formats); err != nil { 85 | if ve, ok := err.(*errors.Validation); ok { 86 | return ve.ValidateName("Header") 87 | } else if ce, ok := err.(*errors.CompositeError); ok { 88 | return ce.ValidateName("Header") 89 | } 90 | return err 91 | } 92 | 93 | return nil 94 | } 95 | 96 | // MarshalBinary interface implementation 97 | func (m *FileHeader) MarshalBinary() ([]byte, error) { 98 | if m == nil { 99 | return nil, nil 100 | } 101 | return swag.WriteJSON(m) 102 | } 103 | 104 | // UnmarshalBinary interface implementation 105 | func (m *FileHeader) UnmarshalBinary(b []byte) error { 106 | var res FileHeader 107 | if err := swag.ReadJSON(b, &res); err != nil { 108 | return err 109 | } 110 | *m = res 111 | return nil 112 | } 113 | -------------------------------------------------------------------------------- /conf/conf.go: -------------------------------------------------------------------------------- 1 | // Package config provides basic configuration plumbing. 2 | package config 3 | 4 | import ( 5 | "encoding/json" 6 | "fmt" 7 | 8 | "github.com/kelseyhightower/envconfig" 9 | 10 | "github.com/TykTechnologies/mserv/util/conf" 11 | "github.com/TykTechnologies/mserv/util/logger" 12 | ) 13 | 14 | type StorageDriver string 15 | 16 | type AWSS3 struct { 17 | ConfigAccessKeyID string 18 | ConfigSecretKey string 19 | ConfigRegion string 20 | } 21 | 22 | type LocalStore struct { 23 | ConfigKeyPath string `default:"/tmp/mserv/filestore-local"` 24 | } 25 | 26 | type FileStorage struct { 27 | S3 *AWSS3 28 | Local *LocalStore 29 | Kind string `default:"local"` 30 | } 31 | 32 | // MservConf describes the settings required for an Mserv instance 33 | type MservConf struct { 34 | StorageTag string 35 | StoreType StorageDriver 36 | 37 | AllowHttpInvocation bool 38 | HTTPAddr string `default:":8989"` 39 | 40 | GrpcServer struct { 41 | Address string 42 | Enabled bool 43 | } 44 | 45 | PublicKeyPath string 46 | MiddlewarePath string `default:"/tmp/mserv/middleware"` 47 | PluginDir string `default:"/tmp/mserv/plugins"` 48 | 49 | RetainUploads bool 50 | 51 | FileStore *FileStorage 52 | } 53 | 54 | type Config struct { 55 | Mserv MservConf 56 | } 57 | 58 | const ( 59 | envPrefix = "MS" 60 | moduleName = "mserv.config" 61 | ) 62 | 63 | var ( 64 | sConf *Config 65 | log = logger.GetLogger(moduleName) 66 | ) 67 | 68 | // Reload the configuration settings from environment and file, in that order. 69 | func Reload() { 70 | sConf = &Config{} 71 | 72 | if err := envconfig.Process(envPrefix, sConf); err != nil { 73 | log.WithError(err).Fatal("failed to process config env vars") 74 | } 75 | 76 | // Make sure the config data we're about to use is fresh 77 | // 78 | // We should consider migrating the 'conf' and 'config' packages to something more capable, like Viper: 79 | // https://github.com/spf13/viper#watching-and-re-reading-config-files 80 | // https://pkg.go.dev/github.com/spf13/viper#OnConfigChange 81 | conf.Flush() 82 | 83 | if err := json.Unmarshal(conf.ReadConf(), sConf); err != nil { 84 | log.WithError(err).Fatal("failed to unmarshal mserv driver config") 85 | } 86 | } 87 | 88 | // GetConf will get the configuration settings for the MServ server. 89 | // Subsequent calls will NOT refresh the settings if they have since changed. 90 | // For that to happen, call Reload first. 91 | var GetConf = func() *Config { 92 | if sConf == nil { 93 | Reload() 94 | } 95 | 96 | return sConf 97 | } 98 | 99 | // GetConf will get the config data for the Momo Driver 100 | var GetSubConf = func(in interface{}, envTag string) error { 101 | if err := envconfig.Process(envTag, in); err != nil { 102 | log.WithError(err).Fatal("failed to process config env vars") 103 | } 104 | 105 | if err := json.Unmarshal(conf.ReadConf(), in); err != nil { 106 | return fmt.Errorf("failed to unmarshal mserv driver config: %w", err) 107 | } 108 | 109 | return nil 110 | } 111 | -------------------------------------------------------------------------------- /mservclient/models/endpoint_method_meta.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/errors" 12 | "github.com/go-openapi/strfmt" 13 | "github.com/go-openapi/swag" 14 | ) 15 | 16 | // EndpointMethodMeta endpoint method meta 17 | // 18 | // swagger:model EndpointMethodMeta 19 | type EndpointMethodMeta struct { 20 | 21 | // code 22 | Code int64 `json:"code,omitempty"` 23 | 24 | // data 25 | Data string `json:"data,omitempty"` 26 | 27 | // headers 28 | Headers map[string]string `json:"headers,omitempty"` 29 | 30 | // action 31 | Action EndpointMethodAction `json:"action,omitempty"` 32 | } 33 | 34 | // Validate validates this endpoint method meta 35 | func (m *EndpointMethodMeta) Validate(formats strfmt.Registry) error { 36 | var res []error 37 | 38 | if err := m.validateAction(formats); err != nil { 39 | res = append(res, err) 40 | } 41 | 42 | if len(res) > 0 { 43 | return errors.CompositeValidationError(res...) 44 | } 45 | return nil 46 | } 47 | 48 | func (m *EndpointMethodMeta) validateAction(formats strfmt.Registry) error { 49 | if swag.IsZero(m.Action) { // not required 50 | return nil 51 | } 52 | 53 | if err := m.Action.Validate(formats); err != nil { 54 | if ve, ok := err.(*errors.Validation); ok { 55 | return ve.ValidateName("action") 56 | } else if ce, ok := err.(*errors.CompositeError); ok { 57 | return ce.ValidateName("action") 58 | } 59 | return err 60 | } 61 | 62 | return nil 63 | } 64 | 65 | // ContextValidate validate this endpoint method meta based on the context it is used 66 | func (m *EndpointMethodMeta) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 67 | var res []error 68 | 69 | if err := m.contextValidateAction(ctx, formats); err != nil { 70 | res = append(res, err) 71 | } 72 | 73 | if len(res) > 0 { 74 | return errors.CompositeValidationError(res...) 75 | } 76 | return nil 77 | } 78 | 79 | func (m *EndpointMethodMeta) contextValidateAction(ctx context.Context, formats strfmt.Registry) error { 80 | 81 | if swag.IsZero(m.Action) { // not required 82 | return nil 83 | } 84 | 85 | if err := m.Action.ContextValidate(ctx, formats); err != nil { 86 | if ve, ok := err.(*errors.Validation); ok { 87 | return ve.ValidateName("action") 88 | } else if ce, ok := err.(*errors.CompositeError); ok { 89 | return ce.ValidateName("action") 90 | } 91 | return err 92 | } 93 | 94 | return nil 95 | } 96 | 97 | // MarshalBinary interface implementation 98 | func (m *EndpointMethodMeta) MarshalBinary() ([]byte, error) { 99 | if m == nil { 100 | return nil, nil 101 | } 102 | return swag.WriteJSON(m) 103 | } 104 | 105 | // UnmarshalBinary interface implementation 106 | func (m *EndpointMethodMeta) UnmarshalBinary(b []byte) error { 107 | var res EndpointMethodMeta 108 | if err := swag.ReadJSON(b, &res); err != nil { 109 | return err 110 | } 111 | *m = res 112 | return nil 113 | } 114 | -------------------------------------------------------------------------------- /coprocess/bindings/go/coprocess_return_overrides.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: coprocess_return_overrides.proto 3 | 4 | package coprocess 5 | 6 | import proto "github.com/golang/protobuf/proto" 7 | import fmt "fmt" 8 | import math "math" 9 | 10 | // Reference imports to suppress errors if they are not otherwise used. 11 | var _ = proto.Marshal 12 | var _ = fmt.Errorf 13 | var _ = math.Inf 14 | 15 | type ReturnOverrides struct { 16 | ResponseCode int32 `protobuf:"varint,1,opt,name=response_code,json=responseCode" json:"response_code,omitempty"` 17 | ResponseError string `protobuf:"bytes,2,opt,name=response_error,json=responseError" json:"response_error,omitempty"` 18 | Headers map[string]string `protobuf:"bytes,3,rep,name=headers" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` 19 | } 20 | 21 | func (m *ReturnOverrides) Reset() { *m = ReturnOverrides{} } 22 | func (m *ReturnOverrides) String() string { return proto.CompactTextString(m) } 23 | func (*ReturnOverrides) ProtoMessage() {} 24 | func (*ReturnOverrides) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{0} } 25 | 26 | func (m *ReturnOverrides) GetResponseCode() int32 { 27 | if m != nil { 28 | return m.ResponseCode 29 | } 30 | return 0 31 | } 32 | 33 | func (m *ReturnOverrides) GetResponseError() string { 34 | if m != nil { 35 | return m.ResponseError 36 | } 37 | return "" 38 | } 39 | 40 | func (m *ReturnOverrides) GetHeaders() map[string]string { 41 | if m != nil { 42 | return m.Headers 43 | } 44 | return nil 45 | } 46 | 47 | func init() { 48 | proto.RegisterType((*ReturnOverrides)(nil), "coprocess.ReturnOverrides") 49 | } 50 | 51 | func init() { proto.RegisterFile("coprocess_return_overrides.proto", fileDescriptor3) } 52 | 53 | var fileDescriptor3 = []byte{ 54 | // 206 bytes of a gzipped FileDescriptorProto 55 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x48, 0xce, 0x2f, 0x28, 56 | 0xca, 0x4f, 0x4e, 0x2d, 0x2e, 0x8e, 0x2f, 0x4a, 0x2d, 0x29, 0x2d, 0xca, 0x8b, 0xcf, 0x2f, 0x4b, 57 | 0x2d, 0x2a, 0xca, 0x4c, 0x49, 0x2d, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x84, 0xab, 58 | 0x50, 0xba, 0xc3, 0xc8, 0xc5, 0x1f, 0x04, 0x56, 0xe5, 0x0f, 0x53, 0x24, 0xa4, 0xcc, 0xc5, 0x5b, 59 | 0x94, 0x5a, 0x5c, 0x90, 0x9f, 0x57, 0x9c, 0x1a, 0x9f, 0x9c, 0x9f, 0x92, 0x2a, 0xc1, 0xa8, 0xc0, 60 | 0xa8, 0xc1, 0x1a, 0xc4, 0x03, 0x13, 0x74, 0xce, 0x4f, 0x49, 0x15, 0x52, 0xe5, 0xe2, 0x83, 0x2b, 61 | 0x4a, 0x2d, 0x2a, 0xca, 0x2f, 0x92, 0x60, 0x52, 0x60, 0xd4, 0xe0, 0x0c, 0x82, 0x6b, 0x75, 0x05, 62 | 0x09, 0x0a, 0x39, 0x72, 0xb1, 0x67, 0xa4, 0x26, 0xa6, 0xa4, 0x16, 0x15, 0x4b, 0x30, 0x2b, 0x30, 63 | 0x6b, 0x70, 0x1b, 0xa9, 0xeb, 0xc1, 0x2d, 0xd7, 0x43, 0xb3, 0x58, 0xcf, 0x03, 0xa2, 0xd2, 0x35, 64 | 0xaf, 0xa4, 0xa8, 0x32, 0x08, 0xa6, 0x4f, 0xca, 0x8a, 0x8b, 0x07, 0x59, 0x42, 0x48, 0x80, 0x8b, 65 | 0x39, 0x3b, 0xb5, 0x12, 0xec, 0x28, 0xce, 0x20, 0x10, 0x53, 0x48, 0x84, 0x8b, 0xb5, 0x2c, 0x31, 66 | 0xa7, 0x34, 0x15, 0xea, 0x04, 0x08, 0xc7, 0x8a, 0xc9, 0x82, 0x31, 0x89, 0x0d, 0xec, 0x61, 0x63, 67 | 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd6, 0x37, 0xa0, 0x22, 0x14, 0x01, 0x00, 0x00, 68 | } 69 | -------------------------------------------------------------------------------- /mservclient/models/template_meta.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/errors" 12 | "github.com/go-openapi/strfmt" 13 | "github.com/go-openapi/swag" 14 | ) 15 | 16 | // TemplateMeta template meta 17 | // 18 | // swagger:model TemplateMeta 19 | type TemplateMeta struct { 20 | 21 | // method 22 | Method string `json:"method,omitempty"` 23 | 24 | // path 25 | Path string `json:"path,omitempty"` 26 | 27 | // template data 28 | TemplateData *TemplateData `json:"template_data,omitempty"` 29 | } 30 | 31 | // Validate validates this template meta 32 | func (m *TemplateMeta) Validate(formats strfmt.Registry) error { 33 | var res []error 34 | 35 | if err := m.validateTemplateData(formats); err != nil { 36 | res = append(res, err) 37 | } 38 | 39 | if len(res) > 0 { 40 | return errors.CompositeValidationError(res...) 41 | } 42 | return nil 43 | } 44 | 45 | func (m *TemplateMeta) validateTemplateData(formats strfmt.Registry) error { 46 | if swag.IsZero(m.TemplateData) { // not required 47 | return nil 48 | } 49 | 50 | if m.TemplateData != nil { 51 | if err := m.TemplateData.Validate(formats); err != nil { 52 | if ve, ok := err.(*errors.Validation); ok { 53 | return ve.ValidateName("template_data") 54 | } else if ce, ok := err.(*errors.CompositeError); ok { 55 | return ce.ValidateName("template_data") 56 | } 57 | return err 58 | } 59 | } 60 | 61 | return nil 62 | } 63 | 64 | // ContextValidate validate this template meta based on the context it is used 65 | func (m *TemplateMeta) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 66 | var res []error 67 | 68 | if err := m.contextValidateTemplateData(ctx, formats); err != nil { 69 | res = append(res, err) 70 | } 71 | 72 | if len(res) > 0 { 73 | return errors.CompositeValidationError(res...) 74 | } 75 | return nil 76 | } 77 | 78 | func (m *TemplateMeta) contextValidateTemplateData(ctx context.Context, formats strfmt.Registry) error { 79 | 80 | if m.TemplateData != nil { 81 | 82 | if swag.IsZero(m.TemplateData) { // not required 83 | return nil 84 | } 85 | 86 | if err := m.TemplateData.ContextValidate(ctx, formats); err != nil { 87 | if ve, ok := err.(*errors.Validation); ok { 88 | return ve.ValidateName("template_data") 89 | } else if ce, ok := err.(*errors.CompositeError); ok { 90 | return ce.ValidateName("template_data") 91 | } 92 | return err 93 | } 94 | } 95 | 96 | return nil 97 | } 98 | 99 | // MarshalBinary interface implementation 100 | func (m *TemplateMeta) MarshalBinary() ([]byte, error) { 101 | if m == nil { 102 | return nil, nil 103 | } 104 | return swag.WriteJSON(m) 105 | } 106 | 107 | // UnmarshalBinary interface implementation 108 | func (m *TemplateMeta) UnmarshalBinary(b []byte) error { 109 | var res TemplateMeta 110 | if err := swag.ReadJSON(b, &res); err != nil { 111 | return err 112 | } 113 | *m = res 114 | return nil 115 | } 116 | -------------------------------------------------------------------------------- /mservclient/models/event_handler_trigger_config.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/errors" 12 | "github.com/go-openapi/strfmt" 13 | "github.com/go-openapi/swag" 14 | ) 15 | 16 | // EventHandlerTriggerConfig event handler trigger config 17 | // 18 | // swagger:model EventHandlerTriggerConfig 19 | type EventHandlerTriggerConfig struct { 20 | 21 | // handler meta 22 | HandlerMeta interface{} `json:"handler_meta,omitempty"` 23 | 24 | // handler name 25 | HandlerName TykEventHandlerName `json:"handler_name,omitempty"` 26 | } 27 | 28 | // Validate validates this event handler trigger config 29 | func (m *EventHandlerTriggerConfig) Validate(formats strfmt.Registry) error { 30 | var res []error 31 | 32 | if err := m.validateHandlerName(formats); err != nil { 33 | res = append(res, err) 34 | } 35 | 36 | if len(res) > 0 { 37 | return errors.CompositeValidationError(res...) 38 | } 39 | return nil 40 | } 41 | 42 | func (m *EventHandlerTriggerConfig) validateHandlerName(formats strfmt.Registry) error { 43 | if swag.IsZero(m.HandlerName) { // not required 44 | return nil 45 | } 46 | 47 | if err := m.HandlerName.Validate(formats); err != nil { 48 | if ve, ok := err.(*errors.Validation); ok { 49 | return ve.ValidateName("handler_name") 50 | } else if ce, ok := err.(*errors.CompositeError); ok { 51 | return ce.ValidateName("handler_name") 52 | } 53 | return err 54 | } 55 | 56 | return nil 57 | } 58 | 59 | // ContextValidate validate this event handler trigger config based on the context it is used 60 | func (m *EventHandlerTriggerConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 61 | var res []error 62 | 63 | if err := m.contextValidateHandlerName(ctx, formats); err != nil { 64 | res = append(res, err) 65 | } 66 | 67 | if len(res) > 0 { 68 | return errors.CompositeValidationError(res...) 69 | } 70 | return nil 71 | } 72 | 73 | func (m *EventHandlerTriggerConfig) contextValidateHandlerName(ctx context.Context, formats strfmt.Registry) error { 74 | 75 | if swag.IsZero(m.HandlerName) { // not required 76 | return nil 77 | } 78 | 79 | if err := m.HandlerName.ContextValidate(ctx, formats); err != nil { 80 | if ve, ok := err.(*errors.Validation); ok { 81 | return ve.ValidateName("handler_name") 82 | } else if ce, ok := err.(*errors.CompositeError); ok { 83 | return ce.ValidateName("handler_name") 84 | } 85 | return err 86 | } 87 | 88 | return nil 89 | } 90 | 91 | // MarshalBinary interface implementation 92 | func (m *EventHandlerTriggerConfig) MarshalBinary() ([]byte, error) { 93 | if m == nil { 94 | return nil, nil 95 | } 96 | return swag.WriteJSON(m) 97 | } 98 | 99 | // UnmarshalBinary interface implementation 100 | func (m *EventHandlerTriggerConfig) UnmarshalBinary(b []byte) error { 101 | var res EventHandlerTriggerConfig 102 | if err := swag.ReadJSON(b, &res); err != nil { 103 | return err 104 | } 105 | *m = res 106 | return nil 107 | } 108 | -------------------------------------------------------------------------------- /util/storage/slave/slave.go: -------------------------------------------------------------------------------- 1 | package slave 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "net/url" 8 | 9 | "github.com/go-openapi/runtime" 10 | httptransport "github.com/go-openapi/runtime/client" 11 | "github.com/sirupsen/logrus" 12 | 13 | "github.com/TykTechnologies/mserv/mservclient/client" 14 | "github.com/TykTechnologies/mserv/mservclient/client/mw" 15 | "github.com/TykTechnologies/mserv/storage" 16 | "github.com/TykTechnologies/mserv/util/logger" 17 | ) 18 | 19 | var ( 20 | moduleName = "mserv.slave" 21 | log = logger.GetLogger(moduleName) 22 | ) 23 | 24 | func NewSlaveClient() (*Client, error) { 25 | return &Client{}, nil 26 | } 27 | 28 | type Client struct { 29 | conf *StoreConf 30 | mservapi *client.MservAPI 31 | tag string 32 | } 33 | 34 | func (c *Client) defaultAuth() runtime.ClientAuthInfoWriter { 35 | return httptransport.APIKeyAuth("X-Api-Key", "header", c.conf.Secret) 36 | } 37 | 38 | func (c *Client) GetMWByID(_ context.Context, id string) (*storage.MW, error) { 39 | params := mw.NewMwFetchParams().WithID(id) 40 | resp, err := c.mservapi.Mw.MwFetch(params, c.defaultAuth()) 41 | if err != nil { 42 | return nil, err 43 | } 44 | 45 | return clientToStorageMW(resp.GetPayload().Payload) 46 | } 47 | 48 | // GetMWByAPIID is not yet implemented. 49 | func (c *Client) GetMWByAPIID(_ context.Context, _ string) (*storage.MW, error) { 50 | return nil, errors.New("not implemented") 51 | } 52 | 53 | func (c *Client) GetAllActive(_ context.Context) ([]*storage.MW, error) { 54 | resp, err := c.mservapi.Mw.MwListAll(mw.NewMwListAllParams(), c.defaultAuth()) 55 | if err != nil { 56 | return nil, err 57 | } 58 | 59 | mws := make([]*storage.MW, 0) 60 | for _, mw := range resp.GetPayload().Payload { 61 | stMW, err := clientToStorageMW(mw) 62 | if err != nil { 63 | return nil, err 64 | } 65 | mws = append(mws, stMW) 66 | } 67 | 68 | return mws, nil 69 | } 70 | 71 | func (c *Client) CreateMW(_ context.Context, _ *storage.MW) (string, error) { 72 | return "", errors.New("not implemented") 73 | } 74 | 75 | func (c *Client) UpdateMW(_ context.Context, _ *storage.MW) (string, error) { 76 | return "", errors.New("not implemented") 77 | } 78 | 79 | func (c *Client) DeleteMW(_ context.Context, _ string) error { 80 | return errors.New("not implemented") 81 | } 82 | 83 | func (c *Client) InitMservStore(_ context.Context, tag string) error { 84 | c.tag = tag 85 | cnf, ok := GetConf().ServiceStore[tag] 86 | if !ok { 87 | return fmt.Errorf("no matching store config tag found for tag: %v", c.tag) 88 | } 89 | 90 | c.conf = cnf 91 | 92 | endpoint, err := parseEndpoint(c.conf.ConnStr) 93 | if err != nil { 94 | return err 95 | } 96 | 97 | tr := httptransport.New(endpoint.Host, endpoint.Path, []string{endpoint.Scheme}) 98 | tr.SetLogger(log) 99 | tr.SetDebug(log.Logger.GetLevel() >= logrus.DebugLevel) 100 | 101 | c.mservapi = client.New(tr, nil) 102 | 103 | log.Info("initialising service store") 104 | return nil 105 | } 106 | 107 | func parseEndpoint(endpoint string) (*url.URL, error) { 108 | parsed, err := url.Parse(endpoint) 109 | if err != nil { 110 | return nil, err 111 | } 112 | return parsed, nil 113 | } 114 | -------------------------------------------------------------------------------- /mservclient/models/end_point_meta.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/errors" 12 | "github.com/go-openapi/strfmt" 13 | "github.com/go-openapi/swag" 14 | "github.com/go-openapi/validate" 15 | ) 16 | 17 | // EndPointMeta end point meta 18 | // 19 | // swagger:model EndPointMeta 20 | type EndPointMeta struct { 21 | 22 | // ignore case 23 | IgnoreCase bool `json:"ignore_case,omitempty"` 24 | 25 | // method actions 26 | MethodActions map[string]EndpointMethodMeta `json:"method_actions,omitempty"` 27 | 28 | // path 29 | Path string `json:"path,omitempty"` 30 | } 31 | 32 | // Validate validates this end point meta 33 | func (m *EndPointMeta) Validate(formats strfmt.Registry) error { 34 | var res []error 35 | 36 | if err := m.validateMethodActions(formats); err != nil { 37 | res = append(res, err) 38 | } 39 | 40 | if len(res) > 0 { 41 | return errors.CompositeValidationError(res...) 42 | } 43 | return nil 44 | } 45 | 46 | func (m *EndPointMeta) validateMethodActions(formats strfmt.Registry) error { 47 | if swag.IsZero(m.MethodActions) { // not required 48 | return nil 49 | } 50 | 51 | for k := range m.MethodActions { 52 | 53 | if err := validate.Required("method_actions"+"."+k, "body", m.MethodActions[k]); err != nil { 54 | return err 55 | } 56 | if val, ok := m.MethodActions[k]; ok { 57 | if err := val.Validate(formats); err != nil { 58 | if ve, ok := err.(*errors.Validation); ok { 59 | return ve.ValidateName("method_actions" + "." + k) 60 | } else if ce, ok := err.(*errors.CompositeError); ok { 61 | return ce.ValidateName("method_actions" + "." + k) 62 | } 63 | return err 64 | } 65 | } 66 | 67 | } 68 | 69 | return nil 70 | } 71 | 72 | // ContextValidate validate this end point meta based on the context it is used 73 | func (m *EndPointMeta) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 74 | var res []error 75 | 76 | if err := m.contextValidateMethodActions(ctx, formats); err != nil { 77 | res = append(res, err) 78 | } 79 | 80 | if len(res) > 0 { 81 | return errors.CompositeValidationError(res...) 82 | } 83 | return nil 84 | } 85 | 86 | func (m *EndPointMeta) contextValidateMethodActions(ctx context.Context, formats strfmt.Registry) error { 87 | 88 | for k := range m.MethodActions { 89 | 90 | if val, ok := m.MethodActions[k]; ok { 91 | if err := val.ContextValidate(ctx, formats); err != nil { 92 | return err 93 | } 94 | } 95 | 96 | } 97 | 98 | return nil 99 | } 100 | 101 | // MarshalBinary interface implementation 102 | func (m *EndPointMeta) MarshalBinary() ([]byte, error) { 103 | if m == nil { 104 | return nil, nil 105 | } 106 | return swag.WriteJSON(m) 107 | } 108 | 109 | // UnmarshalBinary interface implementation 110 | func (m *EndPointMeta) UnmarshalBinary(b []byte) error { 111 | var res EndPointMeta 112 | if err := swag.ReadJSON(b, &res); err != nil { 113 | return err 114 | } 115 | *m = res 116 | return nil 117 | } 118 | -------------------------------------------------------------------------------- /mservclient/models/bundle_manifest.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/errors" 12 | "github.com/go-openapi/strfmt" 13 | "github.com/go-openapi/swag" 14 | ) 15 | 16 | // BundleManifest bundle manifest 17 | // 18 | // swagger:model BundleManifest 19 | type BundleManifest struct { 20 | 21 | // checksum 22 | Checksum string `json:"checksum,omitempty"` 23 | 24 | // file list 25 | FileList []string `json:"file_list"` 26 | 27 | // signature 28 | Signature string `json:"signature,omitempty"` 29 | 30 | // custom middleware 31 | CustomMiddleware *MiddlewareSection `json:"custom_middleware,omitempty"` 32 | } 33 | 34 | // Validate validates this bundle manifest 35 | func (m *BundleManifest) Validate(formats strfmt.Registry) error { 36 | var res []error 37 | 38 | if err := m.validateCustomMiddleware(formats); err != nil { 39 | res = append(res, err) 40 | } 41 | 42 | if len(res) > 0 { 43 | return errors.CompositeValidationError(res...) 44 | } 45 | return nil 46 | } 47 | 48 | func (m *BundleManifest) validateCustomMiddleware(formats strfmt.Registry) error { 49 | if swag.IsZero(m.CustomMiddleware) { // not required 50 | return nil 51 | } 52 | 53 | if m.CustomMiddleware != nil { 54 | if err := m.CustomMiddleware.Validate(formats); err != nil { 55 | if ve, ok := err.(*errors.Validation); ok { 56 | return ve.ValidateName("custom_middleware") 57 | } else if ce, ok := err.(*errors.CompositeError); ok { 58 | return ce.ValidateName("custom_middleware") 59 | } 60 | return err 61 | } 62 | } 63 | 64 | return nil 65 | } 66 | 67 | // ContextValidate validate this bundle manifest based on the context it is used 68 | func (m *BundleManifest) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 69 | var res []error 70 | 71 | if err := m.contextValidateCustomMiddleware(ctx, formats); err != nil { 72 | res = append(res, err) 73 | } 74 | 75 | if len(res) > 0 { 76 | return errors.CompositeValidationError(res...) 77 | } 78 | return nil 79 | } 80 | 81 | func (m *BundleManifest) contextValidateCustomMiddleware(ctx context.Context, formats strfmt.Registry) error { 82 | 83 | if m.CustomMiddleware != nil { 84 | 85 | if swag.IsZero(m.CustomMiddleware) { // not required 86 | return nil 87 | } 88 | 89 | if err := m.CustomMiddleware.ContextValidate(ctx, formats); err != nil { 90 | if ve, ok := err.(*errors.Validation); ok { 91 | return ve.ValidateName("custom_middleware") 92 | } else if ce, ok := err.(*errors.CompositeError); ok { 93 | return ce.ValidateName("custom_middleware") 94 | } 95 | return err 96 | } 97 | } 98 | 99 | return nil 100 | } 101 | 102 | // MarshalBinary interface implementation 103 | func (m *BundleManifest) MarshalBinary() ([]byte, error) { 104 | if m == nil { 105 | return nil, nil 106 | } 107 | return swag.WriteJSON(m) 108 | } 109 | 110 | // UnmarshalBinary interface implementation 111 | func (m *BundleManifest) UnmarshalBinary(b []byte) error { 112 | var res BundleManifest 113 | if err := swag.ReadJSON(b, &res); err != nil { 114 | return err 115 | } 116 | *m = res 117 | return nil 118 | } 119 | -------------------------------------------------------------------------------- /storage/runtime_storage.go: -------------------------------------------------------------------------------- 1 | // Package storage defines a runtime store and associated types for use with mserv. 2 | package storage 3 | 4 | import ( 5 | "errors" 6 | "fmt" 7 | "sync" 8 | 9 | "github.com/TykTechnologies/tyk/apidef" 10 | 11 | coprocess "github.com/TykTechnologies/mserv/coprocess/bindings/go" 12 | ) 13 | 14 | var GlobalRtStore *RuntimeStore 15 | 16 | type RuntimeStore struct { 17 | manifests sync.Map 18 | functions sync.Map 19 | } 20 | 21 | func NewRuntimeStore() *RuntimeStore { 22 | return &RuntimeStore{ 23 | manifests: sync.Map{}, 24 | functions: sync.Map{}, 25 | } 26 | } 27 | 28 | func GenerateStoreKey(org, api, hType, name string) string { 29 | return fmt.Sprintf("%s.%s", hType, name) 30 | } 31 | 32 | func (s *RuntimeStore) GetManifest(apiID string) (*apidef.BundleManifest, error) { 33 | bm, ok := s.manifests.Load(apiID) 34 | if !ok { 35 | return nil, errors.New("not found") 36 | } 37 | 38 | manifest, ok := bm.(*apidef.BundleManifest) 39 | if !ok { 40 | return nil, errors.New("data is not a bundle manifest") 41 | } 42 | 43 | return manifest, nil 44 | } 45 | 46 | func (s *RuntimeStore) GetHookFunc(name string) (func(*coprocess.Object) (*coprocess.Object, error), error) { 47 | hf, ok := s.functions.Load(name) 48 | if !ok { 49 | return nil, errors.New("not found") 50 | } 51 | 52 | hook, ok := hf.(func(*coprocess.Object) (*coprocess.Object, error)) 53 | if !ok { 54 | return nil, errors.New("data is not a hook function") 55 | } 56 | 57 | return hook, nil 58 | } 59 | 60 | func (s *RuntimeStore) UpdateOrStoreManifest(apiID string, manifest *apidef.BundleManifest) (bool, error) { 61 | _, updated := s.manifests.Load(apiID) 62 | 63 | s.manifests.Store(apiID, manifest) 64 | 65 | return updated, nil 66 | } 67 | 68 | func (s *RuntimeStore) UpdateOrStoreHook(name string, hook func(*coprocess.Object) (*coprocess.Object, error)) (bool, error) { 69 | _, updated := s.functions.Load(name) 70 | 71 | s.functions.Store(name, hook) 72 | 73 | return updated, nil 74 | } 75 | 76 | type DiffReport struct { 77 | Added []*MW 78 | Removed []*MW 79 | } 80 | 81 | func (s *RuntimeStore) FilterNewMW(fetched []*MW) (*DiffReport, error) { 82 | diff := &DiffReport{ 83 | Added: make([]*MW, 0), 84 | Removed: make([]*MW, 0), 85 | } 86 | 87 | s.manifests.Range(func(key, value interface{}) bool { 88 | found := false 89 | for _, fo := range fetched { 90 | if key == fo.UID { 91 | found = true 92 | } 93 | } 94 | 95 | // In loaded list, but not fetched list, so must be deleted 96 | if !found { 97 | diff.Removed = append(diff.Removed, value.(*MW)) 98 | } 99 | 100 | return true 101 | }) 102 | 103 | for _, o := range fetched { 104 | // fmt.Printf("checking %s\n", o.UID) 105 | iMw, exists := s.manifests.Load(o.UID) 106 | if exists { 107 | mw, ok := iMw.(*MW) 108 | if !ok { 109 | return nil, fmt.Errorf("mw not the correct type: %v", o.UID) 110 | } 111 | 112 | // fmt.Printf("comparing %v to %v\n", mw.Added, o.Added) 113 | if mw.Added == o.Added { 114 | // no change, skip 115 | continue 116 | } 117 | } 118 | 119 | // doesn't exist, and has not been updated 120 | // fmt.Printf("%s does not exist, adding to diff\n", o.UID) 121 | diff.Added = append(diff.Added, o) 122 | } 123 | 124 | return diff, nil 125 | } 126 | 127 | func (s *RuntimeStore) AddMW(name string, mw *MW) { 128 | s.manifests.Store(name, mw) 129 | } 130 | -------------------------------------------------------------------------------- /mservclient/models/open_id_options.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | "strconv" 11 | 12 | "github.com/go-openapi/errors" 13 | "github.com/go-openapi/strfmt" 14 | "github.com/go-openapi/swag" 15 | ) 16 | 17 | // OpenIDOptions open ID options 18 | // 19 | // swagger:model OpenIDOptions 20 | type OpenIDOptions struct { 21 | 22 | // providers 23 | Providers []*OIDProviderConfig `json:"providers"` 24 | 25 | // segregate by client 26 | SegregateByClient bool `json:"segregate_by_client,omitempty"` 27 | } 28 | 29 | // Validate validates this open ID options 30 | func (m *OpenIDOptions) Validate(formats strfmt.Registry) error { 31 | var res []error 32 | 33 | if err := m.validateProviders(formats); err != nil { 34 | res = append(res, err) 35 | } 36 | 37 | if len(res) > 0 { 38 | return errors.CompositeValidationError(res...) 39 | } 40 | return nil 41 | } 42 | 43 | func (m *OpenIDOptions) validateProviders(formats strfmt.Registry) error { 44 | if swag.IsZero(m.Providers) { // not required 45 | return nil 46 | } 47 | 48 | for i := 0; i < len(m.Providers); i++ { 49 | if swag.IsZero(m.Providers[i]) { // not required 50 | continue 51 | } 52 | 53 | if m.Providers[i] != nil { 54 | if err := m.Providers[i].Validate(formats); err != nil { 55 | if ve, ok := err.(*errors.Validation); ok { 56 | return ve.ValidateName("providers" + "." + strconv.Itoa(i)) 57 | } else if ce, ok := err.(*errors.CompositeError); ok { 58 | return ce.ValidateName("providers" + "." + strconv.Itoa(i)) 59 | } 60 | return err 61 | } 62 | } 63 | 64 | } 65 | 66 | return nil 67 | } 68 | 69 | // ContextValidate validate this open ID options based on the context it is used 70 | func (m *OpenIDOptions) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 71 | var res []error 72 | 73 | if err := m.contextValidateProviders(ctx, formats); err != nil { 74 | res = append(res, err) 75 | } 76 | 77 | if len(res) > 0 { 78 | return errors.CompositeValidationError(res...) 79 | } 80 | return nil 81 | } 82 | 83 | func (m *OpenIDOptions) contextValidateProviders(ctx context.Context, formats strfmt.Registry) error { 84 | 85 | for i := 0; i < len(m.Providers); i++ { 86 | 87 | if m.Providers[i] != nil { 88 | 89 | if swag.IsZero(m.Providers[i]) { // not required 90 | return nil 91 | } 92 | 93 | if err := m.Providers[i].ContextValidate(ctx, formats); err != nil { 94 | if ve, ok := err.(*errors.Validation); ok { 95 | return ve.ValidateName("providers" + "." + strconv.Itoa(i)) 96 | } else if ce, ok := err.(*errors.CompositeError); ok { 97 | return ce.ValidateName("providers" + "." + strconv.Itoa(i)) 98 | } 99 | return err 100 | } 101 | } 102 | 103 | } 104 | 105 | return nil 106 | } 107 | 108 | // MarshalBinary interface implementation 109 | func (m *OpenIDOptions) MarshalBinary() ([]byte, error) { 110 | if m == nil { 111 | return nil, nil 112 | } 113 | return swag.WriteJSON(m) 114 | } 115 | 116 | // UnmarshalBinary interface implementation 117 | func (m *OpenIDOptions) UnmarshalBinary(b []byte) error { 118 | var res OpenIDOptions 119 | if err := swag.ReadJSON(b, &res); err != nil { 120 | return err 121 | } 122 | *m = res 123 | return nil 124 | } 125 | -------------------------------------------------------------------------------- /doc/swagger.go: -------------------------------------------------------------------------------- 1 | // Package mserv Mserv API. 2 | // 3 | // Provides access to operations over an Mserv service. 4 | // 5 | // Schemes: http, https 6 | // BasePath: / 7 | // Host: localhost:8989 8 | // Version: 0.0.1 9 | // 10 | // Consumes: 11 | // - application/json 12 | // 13 | // Produces: 14 | // - application/json 15 | // 16 | // Security: 17 | // - api_key 18 | // 19 | // SecurityDefinitions: 20 | // api_key: 21 | // type: apiKey 22 | // name: X-Api-Key 23 | // in: header 24 | // 25 | // swagger:meta 26 | package doc 27 | 28 | import ( 29 | coprocess "github.com/TykTechnologies/mserv/coprocess/bindings/go" 30 | "github.com/TykTechnologies/mserv/health" 31 | "github.com/TykTechnologies/mserv/models" 32 | "github.com/TykTechnologies/mserv/storage" 33 | "github.com/go-openapi/runtime" 34 | ) 35 | 36 | // Generic error specified by `Status` and `Error` fields 37 | // swagger:response genericErrorResponse 38 | type GenericErrorResponse struct { 39 | // in: body 40 | Body models.Payload 41 | } 42 | 43 | // Health status response 44 | // swagger:response healthResponse 45 | type HealthResponse struct { 46 | // in: body 47 | Body struct { 48 | models.BasePayload 49 | Payload health.HReport 50 | } 51 | } 52 | 53 | // Middleware invocation response 54 | // swagger:response invocationResponse 55 | type InvocationResponse struct { 56 | // in: body 57 | Body struct { 58 | models.BasePayload 59 | Payload coprocess.Object 60 | } 61 | } 62 | 63 | // Response that only includes the ID of the middleware as `BundleID` in the `Payload` 64 | // swagger:response mwIDResponse 65 | type MiddlewareIDResponse struct { 66 | // in: body 67 | Body struct { 68 | models.BasePayload 69 | Payload struct { 70 | BundleID string 71 | } 72 | } 73 | } 74 | 75 | // Full middleware response in the `Payload` 76 | // swagger:response mwResponse 77 | type MiddlewareResponse struct { 78 | // in: body 79 | Body struct { 80 | models.BasePayload 81 | Payload storage.MW 82 | } 83 | } 84 | 85 | // List of full middleware representations in the `Payload` 86 | // swagger:response mwListResponse 87 | type MiddlewareListResponse struct { 88 | // in: body 89 | Body struct { 90 | models.BasePayload 91 | Payload []storage.MW 92 | } 93 | } 94 | 95 | // Middleware bundle as a file 96 | // swagger:response mwBundleResponse 97 | type MiddlewareBundleResponse struct { 98 | // in: body 99 | File runtime.File 100 | } 101 | 102 | // swagger:parameters mwDelete mwFetch mwFetchBundle 103 | type GenericMiddlewareParameters struct { 104 | // in: path 105 | // required: true 106 | ID string `json:"id"` 107 | } 108 | 109 | // swagger:parameters invoke 110 | type InvocationParameters struct { 111 | // in: path 112 | // required: true 113 | Name string `json:"name"` 114 | // in: body 115 | // required: true 116 | Body coprocess.Object 117 | } 118 | 119 | // swagger:parameters mwAdd 120 | type AddMiddlewareParameters struct { 121 | // in: formData 122 | // required: true 123 | // swagger:file 124 | UploadFile runtime.File `json:"uploadfile"` 125 | // in: query 126 | StoreOnly bool `json:"store_only"` 127 | // in: query 128 | APIID string `json:"api_id"` 129 | } 130 | 131 | // swagger:parameters mwUpdate 132 | type UpdateMiddlewareParameters struct { 133 | GenericMiddlewareParameters 134 | // in: formData 135 | // required: true 136 | // swagger:file 137 | UploadFile runtime.File `json:"uploadfile"` 138 | } 139 | -------------------------------------------------------------------------------- /mservclient/models/auth_config.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/go-openapi/errors" 12 | "github.com/go-openapi/strfmt" 13 | "github.com/go-openapi/swag" 14 | ) 15 | 16 | // AuthConfig auth config 17 | // 18 | // swagger:model AuthConfig 19 | type AuthConfig struct { 20 | 21 | // auth header name 22 | AuthHeaderName string `json:"auth_header_name,omitempty"` 23 | 24 | // cookie name 25 | CookieName string `json:"cookie_name,omitempty"` 26 | 27 | // param name 28 | ParamName string `json:"param_name,omitempty"` 29 | 30 | // use certificate 31 | UseCertificate bool `json:"use_certificate,omitempty"` 32 | 33 | // use cookie 34 | UseCookie bool `json:"use_cookie,omitempty"` 35 | 36 | // use param 37 | UseParam bool `json:"use_param,omitempty"` 38 | 39 | // validate signature 40 | ValidateSignature bool `json:"validate_signature,omitempty"` 41 | 42 | // signature 43 | Signature *SignatureConfig `json:"signature,omitempty"` 44 | } 45 | 46 | // Validate validates this auth config 47 | func (m *AuthConfig) Validate(formats strfmt.Registry) error { 48 | var res []error 49 | 50 | if err := m.validateSignature(formats); err != nil { 51 | res = append(res, err) 52 | } 53 | 54 | if len(res) > 0 { 55 | return errors.CompositeValidationError(res...) 56 | } 57 | return nil 58 | } 59 | 60 | func (m *AuthConfig) validateSignature(formats strfmt.Registry) error { 61 | if swag.IsZero(m.Signature) { // not required 62 | return nil 63 | } 64 | 65 | if m.Signature != nil { 66 | if err := m.Signature.Validate(formats); err != nil { 67 | if ve, ok := err.(*errors.Validation); ok { 68 | return ve.ValidateName("signature") 69 | } else if ce, ok := err.(*errors.CompositeError); ok { 70 | return ce.ValidateName("signature") 71 | } 72 | return err 73 | } 74 | } 75 | 76 | return nil 77 | } 78 | 79 | // ContextValidate validate this auth config based on the context it is used 80 | func (m *AuthConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 81 | var res []error 82 | 83 | if err := m.contextValidateSignature(ctx, formats); err != nil { 84 | res = append(res, err) 85 | } 86 | 87 | if len(res) > 0 { 88 | return errors.CompositeValidationError(res...) 89 | } 90 | return nil 91 | } 92 | 93 | func (m *AuthConfig) contextValidateSignature(ctx context.Context, formats strfmt.Registry) error { 94 | 95 | if m.Signature != nil { 96 | 97 | if swag.IsZero(m.Signature) { // not required 98 | return nil 99 | } 100 | 101 | if err := m.Signature.ContextValidate(ctx, formats); err != nil { 102 | if ve, ok := err.(*errors.Validation); ok { 103 | return ve.ValidateName("signature") 104 | } else if ce, ok := err.(*errors.CompositeError); ok { 105 | return ce.ValidateName("signature") 106 | } 107 | return err 108 | } 109 | } 110 | 111 | return nil 112 | } 113 | 114 | // MarshalBinary interface implementation 115 | func (m *AuthConfig) MarshalBinary() ([]byte, error) { 116 | if m == nil { 117 | return nil, nil 118 | } 119 | return swag.WriteJSON(m) 120 | } 121 | 122 | // UnmarshalBinary interface implementation 123 | func (m *AuthConfig) UnmarshalBinary(b []byte) error { 124 | var res AuthConfig 125 | if err := swag.ReadJSON(b, &res); err != nil { 126 | return err 127 | } 128 | *m = res 129 | return nil 130 | } 131 | -------------------------------------------------------------------------------- /mservclient/models/event_handler_meta_config.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | "strconv" 11 | 12 | "github.com/go-openapi/errors" 13 | "github.com/go-openapi/strfmt" 14 | "github.com/go-openapi/swag" 15 | "github.com/go-openapi/validate" 16 | ) 17 | 18 | // EventHandlerMetaConfig event handler meta config 19 | // 20 | // swagger:model EventHandlerMetaConfig 21 | type EventHandlerMetaConfig struct { 22 | 23 | // events 24 | Events map[string][]EventHandlerTriggerConfig `json:"events,omitempty"` 25 | } 26 | 27 | // Validate validates this event handler meta config 28 | func (m *EventHandlerMetaConfig) Validate(formats strfmt.Registry) error { 29 | var res []error 30 | 31 | if err := m.validateEvents(formats); err != nil { 32 | res = append(res, err) 33 | } 34 | 35 | if len(res) > 0 { 36 | return errors.CompositeValidationError(res...) 37 | } 38 | return nil 39 | } 40 | 41 | func (m *EventHandlerMetaConfig) validateEvents(formats strfmt.Registry) error { 42 | if swag.IsZero(m.Events) { // not required 43 | return nil 44 | } 45 | 46 | for k := range m.Events { 47 | 48 | if err := validate.Required("events"+"."+k, "body", m.Events[k]); err != nil { 49 | return err 50 | } 51 | 52 | for i := 0; i < len(m.Events[k]); i++ { 53 | 54 | if err := m.Events[k][i].Validate(formats); err != nil { 55 | if ve, ok := err.(*errors.Validation); ok { 56 | return ve.ValidateName("events" + "." + k + "." + strconv.Itoa(i)) 57 | } else if ce, ok := err.(*errors.CompositeError); ok { 58 | return ce.ValidateName("events" + "." + k + "." + strconv.Itoa(i)) 59 | } 60 | return err 61 | } 62 | 63 | } 64 | 65 | } 66 | 67 | return nil 68 | } 69 | 70 | // ContextValidate validate this event handler meta config based on the context it is used 71 | func (m *EventHandlerMetaConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 72 | var res []error 73 | 74 | if err := m.contextValidateEvents(ctx, formats); err != nil { 75 | res = append(res, err) 76 | } 77 | 78 | if len(res) > 0 { 79 | return errors.CompositeValidationError(res...) 80 | } 81 | return nil 82 | } 83 | 84 | func (m *EventHandlerMetaConfig) contextValidateEvents(ctx context.Context, formats strfmt.Registry) error { 85 | 86 | for k := range m.Events { 87 | 88 | for i := 0; i < len(m.Events[k]); i++ { 89 | 90 | if swag.IsZero(m.Events[k][i]) { // not required 91 | return nil 92 | } 93 | 94 | if err := m.Events[k][i].ContextValidate(ctx, formats); err != nil { 95 | if ve, ok := err.(*errors.Validation); ok { 96 | return ve.ValidateName("events" + "." + k + "." + strconv.Itoa(i)) 97 | } else if ce, ok := err.(*errors.CompositeError); ok { 98 | return ce.ValidateName("events" + "." + k + "." + strconv.Itoa(i)) 99 | } 100 | return err 101 | } 102 | 103 | } 104 | 105 | } 106 | 107 | return nil 108 | } 109 | 110 | // MarshalBinary interface implementation 111 | func (m *EventHandlerMetaConfig) MarshalBinary() ([]byte, error) { 112 | if m == nil { 113 | return nil, nil 114 | } 115 | return swag.WriteJSON(m) 116 | } 117 | 118 | // UnmarshalBinary interface implementation 119 | func (m *EventHandlerMetaConfig) UnmarshalBinary(b []byte) error { 120 | var res EventHandlerMetaConfig 121 | if err := swag.ReadJSON(b, &res); err != nil { 122 | return err 123 | } 124 | *m = res 125 | return nil 126 | } 127 | -------------------------------------------------------------------------------- /mservclient/models/url_rewrite_meta.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package models 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | "strconv" 11 | 12 | "github.com/go-openapi/errors" 13 | "github.com/go-openapi/strfmt" 14 | "github.com/go-openapi/swag" 15 | ) 16 | 17 | // URLRewriteMeta URL rewrite meta 18 | // 19 | // swagger:model URLRewriteMeta 20 | type URLRewriteMeta struct { 21 | 22 | // match pattern 23 | MatchPattern string `json:"match_pattern,omitempty"` 24 | 25 | // method 26 | Method string `json:"method,omitempty"` 27 | 28 | // path 29 | Path string `json:"path,omitempty"` 30 | 31 | // rewrite to 32 | RewriteTo string `json:"rewrite_to,omitempty"` 33 | 34 | // triggers 35 | Triggers []*RoutingTrigger `json:"triggers"` 36 | } 37 | 38 | // Validate validates this URL rewrite meta 39 | func (m *URLRewriteMeta) Validate(formats strfmt.Registry) error { 40 | var res []error 41 | 42 | if err := m.validateTriggers(formats); err != nil { 43 | res = append(res, err) 44 | } 45 | 46 | if len(res) > 0 { 47 | return errors.CompositeValidationError(res...) 48 | } 49 | return nil 50 | } 51 | 52 | func (m *URLRewriteMeta) validateTriggers(formats strfmt.Registry) error { 53 | if swag.IsZero(m.Triggers) { // not required 54 | return nil 55 | } 56 | 57 | for i := 0; i < len(m.Triggers); i++ { 58 | if swag.IsZero(m.Triggers[i]) { // not required 59 | continue 60 | } 61 | 62 | if m.Triggers[i] != nil { 63 | if err := m.Triggers[i].Validate(formats); err != nil { 64 | if ve, ok := err.(*errors.Validation); ok { 65 | return ve.ValidateName("triggers" + "." + strconv.Itoa(i)) 66 | } else if ce, ok := err.(*errors.CompositeError); ok { 67 | return ce.ValidateName("triggers" + "." + strconv.Itoa(i)) 68 | } 69 | return err 70 | } 71 | } 72 | 73 | } 74 | 75 | return nil 76 | } 77 | 78 | // ContextValidate validate this URL rewrite meta based on the context it is used 79 | func (m *URLRewriteMeta) ContextValidate(ctx context.Context, formats strfmt.Registry) error { 80 | var res []error 81 | 82 | if err := m.contextValidateTriggers(ctx, formats); err != nil { 83 | res = append(res, err) 84 | } 85 | 86 | if len(res) > 0 { 87 | return errors.CompositeValidationError(res...) 88 | } 89 | return nil 90 | } 91 | 92 | func (m *URLRewriteMeta) contextValidateTriggers(ctx context.Context, formats strfmt.Registry) error { 93 | 94 | for i := 0; i < len(m.Triggers); i++ { 95 | 96 | if m.Triggers[i] != nil { 97 | 98 | if swag.IsZero(m.Triggers[i]) { // not required 99 | return nil 100 | } 101 | 102 | if err := m.Triggers[i].ContextValidate(ctx, formats); err != nil { 103 | if ve, ok := err.(*errors.Validation); ok { 104 | return ve.ValidateName("triggers" + "." + strconv.Itoa(i)) 105 | } else if ce, ok := err.(*errors.CompositeError); ok { 106 | return ce.ValidateName("triggers" + "." + strconv.Itoa(i)) 107 | } 108 | return err 109 | } 110 | } 111 | 112 | } 113 | 114 | return nil 115 | } 116 | 117 | // MarshalBinary interface implementation 118 | func (m *URLRewriteMeta) MarshalBinary() ([]byte, error) { 119 | if m == nil { 120 | return nil, nil 121 | } 122 | return swag.WriteJSON(m) 123 | } 124 | 125 | // UnmarshalBinary interface implementation 126 | func (m *URLRewriteMeta) UnmarshalBinary(b []byte) error { 127 | var res URLRewriteMeta 128 | if err := swag.ReadJSON(b, &res); err != nil { 129 | return err 130 | } 131 | *m = res 132 | return nil 133 | } 134 | -------------------------------------------------------------------------------- /bundles/serverless-aws/aws.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/TykTechnologies/mserv/coprocess/bindings/go" 6 | "github.com/TykTechnologies/serverless/provider" 7 | "github.com/TykTechnologies/serverless/provider/aws" 8 | "github.com/sirupsen/logrus" 9 | "os" 10 | ) 11 | 12 | // svlConf is the config_data object sent by the gateway 13 | type svlConf struct { 14 | FuncName string `json:"func_name"` 15 | Version string `json:"version"` 16 | } 17 | 18 | // AWSCaller has all the functionality needed to call 19 | // AWS lambda functions we wrap all calling functionality 20 | // in an object so we don't pollute the global mserv namespace 21 | type AWSCaller struct { 22 | log *logrus.Entry 23 | client provider.Provider 24 | functionList []provider.Function 25 | initialised bool 26 | } 27 | 28 | func (a *AWSCaller) init() { 29 | if a.log == nil { 30 | a.log = logrus.New().WithField("plugin", "aws-caller") 31 | a.log.Info("log initialised") 32 | } 33 | 34 | if a.functionList == nil { 35 | a.functionList = make([]provider.Function, 0) 36 | } 37 | 38 | a.initialised = true 39 | } 40 | 41 | func (a *AWSCaller) initClient() error { 42 | a.log.Info("initialising provider") 43 | var err error 44 | 45 | // cache the client 46 | a.client, err = provider.GetProvider("aws-lambda") 47 | if err != nil { 48 | a.log.Error("failed to load provider: ", err) 49 | return err 50 | } 51 | 52 | reg := os.Getenv("AWS_REGION") 53 | if reg == "" { 54 | a.log.Warn("env AWS_REGION unset, defaulting to us-east-1") 55 | reg = "us-east-1" 56 | } 57 | 58 | conf := &aws.AWSConf{ 59 | Region: reg, 60 | } 61 | 62 | err = a.client.Init(conf) 63 | if err != nil { 64 | a.log.Error("failed to initialise AWS client: ", err) 65 | return err 66 | } 67 | 68 | // cache the func list 69 | if len(a.functionList) == 0 { 70 | a.functionList, err = a.client.List() 71 | a.log.Debug("function list initialised, is: ", a.functionList) 72 | if err != nil { 73 | a.log.Error("failed to load function list: ", err) 74 | return nil 75 | } 76 | } 77 | 78 | return nil 79 | } 80 | 81 | // CallAWS will call the actual AWS lambda 82 | // function, this is the gRPC function invoked 83 | // by the gateway middleware client 84 | func (a *AWSCaller) CallAWS(object *coprocess.Object) (*coprocess.Object, error) { 85 | // first call initialises object 86 | if !a.initialised { 87 | a.init() 88 | } 89 | 90 | // Make sue the client is initialised 91 | if a.client == nil { 92 | err := a.initClient() 93 | if err != nil { 94 | return object, err 95 | } 96 | } 97 | 98 | iCpConf, ok := object.Spec["config_data"] 99 | if !ok { 100 | return object, nil 101 | } 102 | 103 | a.log.Info("supplied config is: ", iCpConf) 104 | 105 | cfg := &svlConf{} 106 | err := json.Unmarshal([]byte(iCpConf), cfg) 107 | if err != nil { 108 | return object, err 109 | } 110 | 111 | a.log.Info("looking to run lambda: ", cfg.FuncName) 112 | for _, f := range a.functionList { 113 | if f.Name == cfg.FuncName { 114 | a.log.Info("found: ", cfg.FuncName) 115 | 116 | // Pass through the body to the lambda function 117 | repl, err := a.client.Invoke(f, []byte(object.Request.Body)) 118 | if err != nil { 119 | return object, err 120 | } 121 | 122 | object.Request.ReturnOverrides.ResponseError = string(repl.GetBody()) 123 | object.Request.ReturnOverrides.ResponseCode = int32(repl.StatusCode) 124 | 125 | return object, nil 126 | } 127 | } 128 | 129 | // pass through 130 | return object, nil 131 | } 132 | 133 | // export symbols 134 | var caller = AWSCaller{} 135 | var CallAWS = caller.CallAWS 136 | -------------------------------------------------------------------------------- /util/storage/mongo/mserv_store.go: -------------------------------------------------------------------------------- 1 | // Package mongo implements Mserv MongoDB storage. 2 | package mongo 3 | 4 | import ( 5 | "context" 6 | "fmt" 7 | 8 | "go.mongodb.org/mongo-driver/bson" 9 | "go.mongodb.org/mongo-driver/bson/primitive" 10 | 11 | "github.com/TykTechnologies/mserv/storage" 12 | ) 13 | 14 | // InitMservStore initializes Mserv storage. 15 | func (m *Store) InitMservStore(_ context.Context, tag string) error { 16 | m.tag = tag 17 | 18 | return m.Init() 19 | } 20 | 21 | // getByKey func fetches middleware from database for give key/value pair. 22 | func (m *Store) getByKey(ctx context.Context, key, value string) (*storage.MW, error) { 23 | mm := mgoMW{} 24 | 25 | f := bson.M{key: value} 26 | 27 | if err := m.db.Collection(mservCol).FindOne(ctx, f).Decode(&mm); err != nil { 28 | return nil, err 29 | } 30 | 31 | return mm.MW, nil 32 | } 33 | 34 | // GetMWByID gets middleware from the store based on its UID. 35 | func (m *Store) GetMWByID(ctx context.Context, id string) (*storage.MW, error) { 36 | return m.getByKey(ctx, "mw.uid", id) 37 | } 38 | 39 | // GetMWByAPIID gets middleware from the store based on its API ID. 40 | func (m *Store) GetMWByAPIID(ctx context.Context, apiID string) (*storage.MW, error) { 41 | return m.getByKey(ctx, "mw.apiid", apiID) 42 | } 43 | 44 | // GetAllActive returns all active middleware from the store. 45 | func (m *Store) GetAllActive(ctx context.Context) ([]*storage.MW, error) { 46 | mm := make([]mgoMW, 0) 47 | 48 | f := bson.M{"mw.active": true} 49 | 50 | cur, err := m.db.Collection(mservCol).Find(ctx, f) 51 | if err != nil { 52 | return nil, fmt.Errorf("collect error: %w", err) 53 | } 54 | 55 | if err := cur.All(ctx, &mm); err != nil { 56 | return nil, fmt.Errorf("cursor fetch error: %w", err) 57 | } 58 | 59 | mws := make([]*storage.MW, len(mm)) 60 | for i, mmw := range mm { 61 | mws[i] = mmw.MW 62 | } 63 | 64 | return mws, nil 65 | } 66 | 67 | // CreateMW stores the given middleware. 68 | func (m *Store) CreateMW(ctx context.Context, mw *storage.MW) (string, error) { 69 | if mw.UID == "" { 70 | return "", ErrEmptyUID 71 | } 72 | 73 | mMw := mgoMW{ 74 | MID: primitive.NewObjectID(), 75 | MW: mw, 76 | } 77 | 78 | if _, err := m.db.Collection(mservCol).InsertOne(ctx, mMw); err != nil { 79 | return "", fmt.Errorf("insert error: %w", err) 80 | } 81 | 82 | return mw.UID, nil 83 | } 84 | 85 | // UpdateMW will update the given middleware in-place in storage. 86 | func (m *Store) UpdateMW(ctx context.Context, mw *storage.MW) (string, error) { 87 | if mw.UID == "" { 88 | return "", ErrEmptyUID 89 | } 90 | 91 | mMw := mgoMW{} 92 | 93 | f := bson.M{"mw.uid": mw.UID} 94 | 95 | if err := m.db.Collection(mservCol).FindOne(ctx, f).Decode(&mMw); err != nil { 96 | return "", fmt.Errorf("find error: %w", err) 97 | } 98 | 99 | mMw.MW = mw 100 | 101 | update := bson.M{ 102 | "$set": mMw, 103 | } 104 | 105 | res, err := m.db.Collection(mservCol).UpdateOne(ctx, f, update) 106 | if err != nil { 107 | return "", fmt.Errorf("update error: %w", err) 108 | } 109 | 110 | if res.MatchedCount == 0 { 111 | return "", ErrNotFound 112 | } 113 | 114 | return mw.UID, nil 115 | } 116 | 117 | // DeleteMW removes given middleware. 118 | func (m *Store) DeleteMW(ctx context.Context, id string) error { 119 | if id == "" { 120 | return ErrEmptyUID 121 | } 122 | 123 | mMw := mgoMW{} 124 | 125 | f := bson.M{"mw.uid": id} 126 | 127 | if err := m.db.Collection(mservCol).FindOne(ctx, f).Decode(&mMw); err != nil { 128 | return fmt.Errorf("find error: %w", err) 129 | } 130 | 131 | if _, err := m.db.Collection(mservCol).DeleteOne(ctx, f); err != nil { 132 | return fmt.Errorf("delete error: %w", err) 133 | } 134 | 135 | return nil 136 | } 137 | -------------------------------------------------------------------------------- /mservctl/cmd/root.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "net/url" 5 | 6 | "github.com/go-openapi/runtime" 7 | httptransport "github.com/go-openapi/runtime/client" 8 | homedir "github.com/mitchellh/go-homedir" 9 | "github.com/sirupsen/logrus" 10 | "github.com/spf13/cobra" 11 | "github.com/spf13/viper" 12 | 13 | "github.com/TykTechnologies/mserv/mservclient/client" 14 | "github.com/TykTechnologies/mserv/util/logger" 15 | ) 16 | 17 | var ( 18 | cfgFile string 19 | mservapi *client.MservAPI 20 | ) 21 | 22 | var log = logger.GetLogger("mservctl") 23 | 24 | // rootCmd represents the base command when called without any subcommands 25 | var rootCmd = &cobra.Command{ 26 | Use: "mservctl", 27 | Short: "CLI to control an Mserv instance", 28 | Long: `mservctl is a CLI application that enables listing and operating middleware in an Mserv instance. 29 | Use a config file (by default at $HOME/.mservctl.yaml) in order to configure the Mserv to use with the CLI. 30 | Alternatively, pass the values with command line arguments. 31 | 32 | Set TYK_MSERV_LOGLEVEL="debug" environment variable to see raw API requests and responses. 33 | `, 34 | Example: "mservctl list -e https://remote.mserv:8989", 35 | } 36 | 37 | // Execute adds all child commands to the root command and sets flags appropriately. 38 | // This is called by main.main(). It only needs to happen once to the rootCmd. 39 | func Execute() { 40 | if err := rootCmd.Execute(); err != nil { 41 | log.Fatal(err) 42 | } 43 | } 44 | 45 | func init() { 46 | cobra.OnInitialize(initConfig) 47 | cobra.OnInitialize(initMservApi) 48 | 49 | rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.mservctl.yaml)") 50 | rootCmd.PersistentFlags().StringP("endpoint", "e", "", "mserv endpoint") 51 | rootCmd.PersistentFlags().StringP("token", "t", "", "mserv security token") 52 | rootCmd.PersistentFlags().BoolP("insecure-tls", "k", false, "allow insecure TLS for mserv client") 53 | 54 | viper.BindPFlag("endpoint", rootCmd.Flag("endpoint")) 55 | viper.BindPFlag("token", rootCmd.Flag("token")) 56 | viper.BindPFlag("insecure_tls", rootCmd.Flag("insecure-tls")) 57 | 58 | viper.SetDefault("endpoint", "http://localhost:8989") 59 | } 60 | 61 | // initConfig reads in config file and ENV variables if set. 62 | func initConfig() { 63 | if cfgFile != "" { 64 | // Use config file from the flag. 65 | viper.SetConfigFile(cfgFile) 66 | } else { 67 | // Find home directory. 68 | home, err := homedir.Dir() 69 | if err != nil { 70 | log.Fatal(err) 71 | } 72 | 73 | // Search config in home directory with name ".mservctl" (without extension). 74 | viper.AddConfigPath(home) 75 | viper.SetConfigName(".mservctl") 76 | } 77 | 78 | viper.AutomaticEnv() // read in environment variables that match 79 | 80 | // If a config file is found, read it in. 81 | if err := viper.ReadInConfig(); err == nil { 82 | log.Info("Using config file:", viper.ConfigFileUsed()) 83 | } 84 | } 85 | 86 | func initMservApi() { 87 | endpoint, err := url.Parse(viper.GetString("endpoint")) 88 | if err != nil { 89 | log.WithError(err).Fatal("Couldn't parse the mserv endpoint") 90 | } 91 | 92 | tlsOptions := httptransport.TLSClientOptions{InsecureSkipVerify: viper.GetBool("insecure_tls")} 93 | tlsClient, err := httptransport.TLSClient(tlsOptions) 94 | if err != nil { 95 | log.WithError(err).Fatal("Couldn't create client with TLS options") 96 | } 97 | 98 | tr := httptransport.NewWithClient(endpoint.Host, endpoint.Path, []string{endpoint.Scheme}, tlsClient) 99 | tr.SetLogger(log) 100 | tr.SetDebug(log.Logger.GetLevel() >= logrus.DebugLevel) 101 | 102 | mservapi = client.New(tr, nil) 103 | } 104 | 105 | func defaultAuth() runtime.ClientAuthInfoWriter { 106 | return httptransport.APIKeyAuth("X-Api-Key", "header", viper.GetString("token")) 107 | } 108 | -------------------------------------------------------------------------------- /http_funcs/api_handlers_delete_test.go: -------------------------------------------------------------------------------- 1 | package http_funcs_test 2 | 3 | import ( 4 | "encoding/json" 5 | "io/ioutil" 6 | "net/http" 7 | "net/http/httptest" 8 | "path/filepath" 9 | "testing" 10 | 11 | "github.com/matryer/is" 12 | 13 | config "github.com/TykTechnologies/mserv/conf" 14 | "github.com/TykTechnologies/mserv/models" 15 | ) 16 | 17 | func TestDeleteMW(t *testing.T) { 18 | is := is.New(t) 19 | srv := setupServerAndTempDir(t) 20 | 21 | t.Run("Deleted middleware does not leave stow.Container behind", func(t *testing.T) { 22 | // Paths to check for things to make sure the handlers are behaving and cleaning up properly 23 | fileCountPath := filepath.Join(config.GetConf().Mserv.MiddlewarePath, "plugins") 24 | localContainerPath := config.GetConf().Mserv.FileStore.Local.ConfigKeyPath 25 | 26 | startFileCount, err := ioutil.ReadDir(fileCountPath) 27 | is.NoErr(err) // could not read 'config.Mserv.MiddlewarePath+"/plugins"' directory 28 | 29 | addReq := prepareAddRequest(t, compressedTestData) 30 | addReq.Form.Add("store_only", "false") // target the 'HandleNewBundle' code path 31 | 32 | // Handle the AddMW request 33 | w := httptest.NewRecorder() 34 | srv.AddMW(w, addReq) 35 | 36 | // Parse the AddMW response 37 | addResp := w.Result() 38 | defer is.NoErr(addResp.Body.Close()) // could not close AddMW response body cleanly 39 | is.Equal(http.StatusOK, addResp.StatusCode) // expected response status does not equal actual from AddMW 40 | 41 | addBod, errRead := ioutil.ReadAll(addResp.Body) 42 | is.NoErr(errRead) // could not read response body 43 | t.Logf("response from %s %s: %s %s", addReq.Method, addReq.URL, addResp.Status, addBod) 44 | 45 | // Confirm that stow created one new container in this test's temp directory 46 | startContainerCount, err := ioutil.ReadDir(localContainerPath) 47 | is.NoErr(err) // could not read directory 48 | is.Equal(1, len(startContainerCount)) // should have one stow.Container after calling AddMW 49 | 50 | // Get ID of added middleware 51 | payload := &models.Payload{} 52 | is.NoErr(json.Unmarshal(addBod, payload)) // could not unmarshal response payload 53 | 54 | internalPayload, ok := payload.Payload.(map[string]interface{}) 55 | is.True(ok) // could not assert type on internal payload 56 | 57 | addedMWID, hasID := internalPayload["BundleID"] 58 | is.True(hasID) // internal payload does not contain "BundleID" 59 | 60 | sAddedMWID, ok := addedMWID.(string) 61 | is.True(ok) // could not assert type on added middleware ID 62 | t.Logf("ID of newly-added middleware: '%s'", sAddedMWID) 63 | 64 | // Do the DeleteMW things 65 | deleteReq := prepareDeleteRequest(t, sAddedMWID) 66 | w = httptest.NewRecorder() // reinitialise 67 | srv.DeleteMW(w, deleteReq) 68 | 69 | // Parse the DeleteMW response 70 | deleteResp := w.Result() 71 | defer is.NoErr(deleteResp.Body.Close()) // could not close DeleteMW response body cleanly 72 | is.Equal(http.StatusOK, deleteResp.StatusCode) // expected response status does not equal actual from DeleteMW 73 | 74 | deleteBod, errRead := ioutil.ReadAll(deleteResp.Body) 75 | is.NoErr(errRead) // could not read response body 76 | t.Logf("response from %s %s: %s %s", deleteReq.Method, deleteReq.URL, deleteResp.Status, deleteBod) 77 | 78 | finishFileCount, err := ioutil.ReadDir(fileCountPath) 79 | is.NoErr(err) // could not read 'config.Mserv.MiddlewarePath+"/plugins"' directory 80 | 81 | is.Equal(len(startFileCount), len(finishFileCount)) // should not leave uploads behind unless configured to do so 82 | 83 | // Confirm that DeleteMW directed stow to clean up after itself 84 | finishContainerCount, err := ioutil.ReadDir(localContainerPath) 85 | is.NoErr(err) // could not read directory 86 | is.Equal(0, len(finishContainerCount)) // should have zero stow.Container after calling DeleteMW 87 | }) 88 | } 89 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL := bash 2 | 3 | # Default - top level rule is what gets run when you run just `make` without specifying a goal/target. 4 | .DEFAULT_GOAL := help 5 | 6 | .DELETE_ON_ERROR: 7 | .ONESHELL: 8 | .SHELLFLAGS := -euo pipefail -c 9 | 10 | MAKEFLAGS += --no-builtin-rules 11 | MAKEFLAGS += --warn-undefined-variables 12 | 13 | export TYK_VERSION := v5.6.1 14 | 15 | ifeq ($(origin .RECIPEPREFIX), undefined) 16 | $(error This Make does not support .RECIPEPREFIX. Please use GNU Make 4.0 or later.) 17 | endif 18 | .RECIPEPREFIX = > 19 | 20 | image_repository ?= tykio/mserv 21 | 22 | # Adjust the width of the first column by changing the '16' value in the printf pattern. 23 | help: 24 | > @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) \ 25 | | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-16s\033[0m %s\n", $$1, $$2}' 26 | .PHONY: help 27 | 28 | check-swagger: 29 | > which swagger || (go get -u github.com/go-swagger/go-swagger/cmd/swagger) 30 | 31 | swagger: check-swagger 32 | > swagger generate spec -o ./doc/swagger.yaml --scan-models -x mservclient 33 | .PHONY: swagger 34 | 35 | serve-swagger: check-swagger 36 | > swagger serve -F=swagger ./doc/swagger.yaml 37 | 38 | swagger-client: check-swagger 39 | > mkdir -p ./mservclient 40 | > swagger generate client -f ./doc/swagger.yaml -t ./mservclient 41 | 42 | clean: ## Clean up the temp and output directories, and any built binaries. This will cause everything to get rebuilt. 43 | > rm -rf ./bin 44 | > rm -rf ./integration/outputs 45 | > go clean 46 | > cd mservctl 47 | > go clean 48 | .PHONY: clean 49 | 50 | clean-docker: ## Clean up any built Docker images. 51 | > docker images \ 52 | --filter=reference=$(image_repository) \ 53 | --no-trunc --quiet | sort -f | uniq | xargs -n 1 docker rmi --force 54 | > rm -f out/image-id 55 | .PHONY: clean-docker 56 | 57 | clean-hack: ## Clean up binaries under 'hack'. 58 | > rm -rf ./hack/bin 59 | .PHONY: clean-hack 60 | 61 | clean-all: clean clean-docker clean-hack ## Clean all of the things. 62 | .PHONY: clean-all 63 | 64 | # Run go tests 65 | test: $(shell find . -type f -iname "*.go") 66 | > mkdir -p $(@D) 67 | > go test -v -count=1 -p 1 -race ./... 68 | 69 | # Lint golangci lint 70 | lint: .golangci.yaml hack/bin/golangci-lint 71 | > mkdir -p $(@D) 72 | > CGO_ENABLED=0 hack/bin/golangci-lint run 73 | 74 | hack/bin/golangci-lint: 75 | > curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh \ 76 | > | sh -s -- -b $(shell pwd)/hack/bin 77 | 78 | docker: Dockerfile ## Builds mserv docker image. 79 | > mkdir -p $(@D) 80 | > image_id="$(image_repository):$(shell uuidgen)" 81 | > DOCKER_BUILDKIT=1 docker build --tag="$${image_id}" . 82 | 83 | build: mserv mservctl ## Build server and client binary. 84 | .PHONY: build 85 | 86 | mserv: 87 | > CGO_ENABLED=0 go build -o bin/mserv 88 | .PHONY: mserv 89 | 90 | mservctl: 91 | > cd mservctl 92 | > CGO_ENABLED=0 go build -o ../bin/mservctl 93 | .PHONY: mservctl 94 | 95 | start: ## Start runs development environment with mserv and mongo in docker compose. 96 | > docker compose up -d 97 | 98 | stop: ## Stop runs development environment with mserv and mongo in docker compose. 99 | > docker compose stop 100 | 101 | # Builds multiple Go plugins and moves them into local Tyk instance. 102 | plugins: 103 | > @for plugin in plugin_1.go plugin_2.go; do \ 104 | > docker compose run --rm tyk-plugin-compiler $$plugin _$$(date +%s); \ 105 | > done 106 | .PHONY: plugins 107 | 108 | bundles: 109 | > docker compose run --rm --workdir /plugin-source --entrypoint "/opt/tyk-gateway/tyk bundle build -y -o bundle.zip" tyk-gateway 110 | .PHONY: bundles 111 | 112 | integration: ## Runs integration test for mserv and mservctl it needs services running. 113 | > cd integration 114 | > venom run integration.yaml -vvv --output-dir outputs 115 | > cd .. 116 | .PHONY: integration 117 | -------------------------------------------------------------------------------- /http_funcs/http_server.go: -------------------------------------------------------------------------------- 1 | package http_funcs 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "net" 7 | "net/http" 8 | "time" 9 | 10 | "github.com/gorilla/mux" 11 | "github.com/rs/cors" 12 | "github.com/sirupsen/logrus" 13 | 14 | "github.com/TykTechnologies/mserv/api" 15 | "github.com/TykTechnologies/mserv/health" 16 | "github.com/TykTechnologies/mserv/models" 17 | "github.com/TykTechnologies/mserv/storage" 18 | "github.com/TykTechnologies/mserv/util/logger" 19 | ) 20 | 21 | var ( 22 | moduleName = "mserv.http" 23 | log = logger.GetLogger(moduleName) 24 | ) 25 | 26 | func NewServer(listenOn string, store storage.MservStore) *HttpServ { 27 | return &HttpServ{ 28 | addr: listenOn, 29 | api: api.NewAPI(store), 30 | } 31 | } 32 | 33 | type HttpServ struct { 34 | api *api.API 35 | addr string 36 | } 37 | 38 | func (h *HttpServ) Listen(m *mux.Router, l net.Listener) error { 39 | srv := &http.Server{ 40 | Handler: m, 41 | Addr: h.addr, 42 | 43 | WriteTimeout: 1 * time.Minute, 44 | ReadTimeout: 1 * time.Minute, 45 | } 46 | 47 | return srv.Serve(l) 48 | } 49 | 50 | // swagger:route GET /health system health 51 | // Query health status of Mserv service. 52 | // 53 | // Responses: 54 | // 200: healthResponse 55 | // 500: healthResponse 56 | func (h *HttpServ) HealthHandler(w http.ResponseWriter, r *http.Request) { 57 | if health.Report.HTTPStarted || health.Report.GRPCStarted { 58 | h.HandleOK(health.Report, w, r) 59 | return 60 | } 61 | 62 | h.writeToClient(w, r, models.NewPayload("error", health.Report, ""), http.StatusInternalServerError) // 500 63 | } 64 | 65 | func (h *HttpServ) HandleError(err error, w http.ResponseWriter, r *http.Request) { 66 | var ( 67 | message string 68 | status int 69 | ) 70 | 71 | switch { 72 | case errors.Is(err, ErrGenericMimeDetected): 73 | message = "unsupported media type" 74 | status = http.StatusUnsupportedMediaType // 415 75 | 76 | case errors.Is(err, ErrUploadNotZip): 77 | message = "unprocessable entity" 78 | status = http.StatusUnprocessableEntity // 422 79 | 80 | default: 81 | message = "internal server error" 82 | status = http.StatusInternalServerError // 500 83 | } 84 | 85 | log.WithError(err).Error(message) 86 | h.writeToClient(w, r, models.NewPayload("error", nil, err.Error()), status) 87 | } 88 | 89 | func (h *HttpServ) HandleOK(payload interface{}, w http.ResponseWriter, r *http.Request) { 90 | h.writeToClient(w, r, models.NewPayload("ok", payload, ""), http.StatusOK) // 200 91 | } 92 | 93 | func (h *HttpServ) writeToClient(w http.ResponseWriter, r *http.Request, payload models.Payload, status int) { 94 | w.Header().Set("Content-Type", "application/json") 95 | w.WriteHeader(status) 96 | 97 | // marshall the payload and handle encoding errors 98 | js, err := json.Marshal(payload) 99 | if err != nil { 100 | // Write big error 101 | es, errMarshal := json.Marshal(models.NewPayload("error", nil, err.Error())) 102 | if errMarshal != nil { 103 | log.WithError(errMarshal).Fatal("This is a terrible place to be") 104 | } 105 | 106 | w.Write(es) 107 | return 108 | } 109 | 110 | w.Write(js) 111 | } 112 | 113 | func setupGlobalMiddleware(handler http.Handler) http.Handler { 114 | co := cors.Options{ 115 | Debug: log.Logger.GetLevel() >= logrus.DebugLevel, 116 | } 117 | 118 | cn := cors.New(co) 119 | cn.Log = &corsDebugWrapper{logger: log} 120 | 121 | handleCORS := cn.Handler 122 | 123 | return handleCORS(handler) 124 | } 125 | 126 | // corsDebugWrapper implements the cors.Logger interface and routes debug logs through the given logger. 127 | type corsDebugWrapper struct { 128 | logger *logrus.Entry 129 | } 130 | 131 | // Printf forwards debugging messages to the logger's debug log level. 132 | func (w *corsDebugWrapper) Printf(format string, args ...interface{}) { 133 | w.logger.Debugf(format, args...) 134 | } 135 | -------------------------------------------------------------------------------- /coprocess/dispatcher/coprocess_grpc.go: -------------------------------------------------------------------------------- 1 | package dispatcher 2 | 3 | import ( 4 | "errors" 5 | "net" 6 | "net/url" 7 | "time" 8 | 9 | "github.com/sirupsen/logrus" 10 | "golang.org/x/net/context" 11 | "google.golang.org/grpc" 12 | 13 | "github.com/TykTechnologies/mserv/coprocess/bindings/go" 14 | "github.com/TykTechnologies/mserv/util/logger" 15 | "github.com/TykTechnologies/tyk/apidef" 16 | "unsafe" 17 | ) 18 | 19 | const ( 20 | _ = iota 21 | JsonMessage 22 | ProtobufMessage 23 | ) 24 | 25 | // CoProcessName specifies the driver name. 26 | const CoProcessName = apidef.GrpcDriver 27 | 28 | // MessageType sets the default message type. 29 | var MessageType = ProtobufMessage 30 | 31 | var grpcConnection *grpc.ClientConn 32 | var grpcClient coprocess.DispatcherClient 33 | var GlobalDispatcher Dispatcher 34 | 35 | var moduleName = "mserv.grpc.dispatcher" 36 | var log = logger.GetLogger(moduleName) 37 | 38 | var gRPCServer = "tcp://127.0.0.1:9898" 39 | 40 | // Dispatcher defines a basic interface for the CP dispatcher, check PythonDispatcher for reference. 41 | type Dispatcher interface { 42 | // Dispatch takes and returns a pointer to a CoProcessMessage struct, see coprocess/api.h for details. This is used by CP bindings. 43 | Dispatch(unsafe.Pointer) unsafe.Pointer 44 | 45 | // DispatchEvent takes an event JSON, as bytes. Doesn't return. 46 | DispatchEvent([]byte) 47 | 48 | // DispatchObject takes and returns a coprocess.Object pointer, this is used by gRPC. 49 | DispatchObject(*coprocess.Object) (*coprocess.Object, error) 50 | } 51 | 52 | // GRPCDispatcher implements a coprocess.Dispatcher 53 | type GRPCDispatcher struct { 54 | Dispatcher 55 | } 56 | 57 | func dialer(addr string, timeout time.Duration) (net.Conn, error) { 58 | grpcUrl, err := url.Parse(gRPCServer) 59 | if err != nil { 60 | log.Error(err) 61 | return nil, err 62 | } 63 | 64 | if grpcUrl == nil { 65 | errString := "No gRPC URL is set!" 66 | log.WithFields(logrus.Fields{ 67 | "prefix": "coprocess-grpc", 68 | }).Error(errString) 69 | return nil, errors.New(errString) 70 | } 71 | 72 | grpcUrlString := gRPCServer[len(grpcUrl.Scheme)+3:] 73 | return net.DialTimeout(grpcUrl.Scheme, grpcUrlString, timeout) 74 | } 75 | 76 | // Dispatch takes a CoProcessMessage and sends it to the CP. 77 | func (d *GRPCDispatcher) DispatchObject(object *coprocess.Object) (*coprocess.Object, error) { 78 | newObject, err := grpcClient.Dispatch(context.Background(), object) 79 | if err != nil { 80 | log.Error("failure to dispatch", err) 81 | } 82 | return newObject, err 83 | } 84 | 85 | // DispatchEvent dispatches a Tyk event. 86 | func (d *GRPCDispatcher) DispatchEvent(eventJSON []byte) { 87 | eventObject := &coprocess.Event{ 88 | Payload: string(eventJSON), 89 | } 90 | 91 | _, err := grpcClient.DispatchEvent(context.Background(), eventObject) 92 | 93 | if err != nil { 94 | log.WithFields(logrus.Fields{ 95 | "prefix": "coprocess-grpc", 96 | }).Error(err) 97 | } 98 | } 99 | 100 | // Reload triggers a reload affecting CP middlewares and event handlers. 101 | func (d *GRPCDispatcher) Reload() {} 102 | 103 | // HandleMiddlewareCache isn't used by gRPC. 104 | func (d *GRPCDispatcher) HandleMiddlewareCache(b *apidef.BundleManifest, basePath string) {} 105 | 106 | // NewCoProcessDispatcher wraps all the actions needed for this CP. 107 | func NewCoProcessDispatcher() (Dispatcher, error) { 108 | log.Info("gRPC server: ", gRPCServer) 109 | if gRPCServer == "" { 110 | return nil, errors.New("no gRPC URL is set") 111 | } 112 | var err error 113 | 114 | log.Info("connecting") 115 | grpcConnection, err = grpc.Dial("", grpc.WithInsecure(), grpc.WithDialer(dialer)) 116 | if err != nil { 117 | log.Error(err) 118 | return nil, err 119 | } 120 | log.Info("connected") 121 | 122 | grpcClient = coprocess.NewDispatcherClient(grpcConnection) 123 | log.Info("set up dispatcher client") 124 | 125 | return &GRPCDispatcher{}, nil 126 | } 127 | -------------------------------------------------------------------------------- /mservclient/client/system/health_parameters.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package system 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "context" 10 | "net/http" 11 | "time" 12 | 13 | "github.com/go-openapi/errors" 14 | "github.com/go-openapi/runtime" 15 | cr "github.com/go-openapi/runtime/client" 16 | "github.com/go-openapi/strfmt" 17 | ) 18 | 19 | // NewHealthParams creates a new HealthParams object, 20 | // with the default timeout for this client. 21 | // 22 | // Default values are not hydrated, since defaults are normally applied by the API server side. 23 | // 24 | // To enforce default values in parameter, use SetDefaults or WithDefaults. 25 | func NewHealthParams() *HealthParams { 26 | return &HealthParams{ 27 | timeout: cr.DefaultTimeout, 28 | } 29 | } 30 | 31 | // NewHealthParamsWithTimeout creates a new HealthParams object 32 | // with the ability to set a timeout on a request. 33 | func NewHealthParamsWithTimeout(timeout time.Duration) *HealthParams { 34 | return &HealthParams{ 35 | timeout: timeout, 36 | } 37 | } 38 | 39 | // NewHealthParamsWithContext creates a new HealthParams object 40 | // with the ability to set a context for a request. 41 | func NewHealthParamsWithContext(ctx context.Context) *HealthParams { 42 | return &HealthParams{ 43 | Context: ctx, 44 | } 45 | } 46 | 47 | // NewHealthParamsWithHTTPClient creates a new HealthParams object 48 | // with the ability to set a custom HTTPClient for a request. 49 | func NewHealthParamsWithHTTPClient(client *http.Client) *HealthParams { 50 | return &HealthParams{ 51 | HTTPClient: client, 52 | } 53 | } 54 | 55 | /* 56 | HealthParams contains all the parameters to send to the API endpoint 57 | 58 | for the health operation. 59 | 60 | Typically these are written to a http.Request. 61 | */ 62 | type HealthParams struct { 63 | timeout time.Duration 64 | Context context.Context 65 | HTTPClient *http.Client 66 | } 67 | 68 | // WithDefaults hydrates default values in the health params (not the query body). 69 | // 70 | // All values with no default are reset to their zero value. 71 | func (o *HealthParams) WithDefaults() *HealthParams { 72 | o.SetDefaults() 73 | return o 74 | } 75 | 76 | // SetDefaults hydrates default values in the health params (not the query body). 77 | // 78 | // All values with no default are reset to their zero value. 79 | func (o *HealthParams) SetDefaults() { 80 | // no default values defined for this parameter 81 | } 82 | 83 | // WithTimeout adds the timeout to the health params 84 | func (o *HealthParams) WithTimeout(timeout time.Duration) *HealthParams { 85 | o.SetTimeout(timeout) 86 | return o 87 | } 88 | 89 | // SetTimeout adds the timeout to the health params 90 | func (o *HealthParams) SetTimeout(timeout time.Duration) { 91 | o.timeout = timeout 92 | } 93 | 94 | // WithContext adds the context to the health params 95 | func (o *HealthParams) WithContext(ctx context.Context) *HealthParams { 96 | o.SetContext(ctx) 97 | return o 98 | } 99 | 100 | // SetContext adds the context to the health params 101 | func (o *HealthParams) SetContext(ctx context.Context) { 102 | o.Context = ctx 103 | } 104 | 105 | // WithHTTPClient adds the HTTPClient to the health params 106 | func (o *HealthParams) WithHTTPClient(client *http.Client) *HealthParams { 107 | o.SetHTTPClient(client) 108 | return o 109 | } 110 | 111 | // SetHTTPClient adds the HTTPClient to the health params 112 | func (o *HealthParams) SetHTTPClient(client *http.Client) { 113 | o.HTTPClient = client 114 | } 115 | 116 | // WriteToRequest writes these params to a swagger request 117 | func (o *HealthParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { 118 | 119 | if err := r.SetTimeout(o.timeout); err != nil { 120 | return err 121 | } 122 | var res []error 123 | 124 | if len(res) > 0 { 125 | return errors.CompositeValidationError(res...) 126 | } 127 | return nil 128 | } 129 | -------------------------------------------------------------------------------- /coprocess/bindings/go/coprocess_common.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: coprocess_common.proto 3 | 4 | /* 5 | Package coprocess is a generated protocol buffer package. 6 | 7 | It is generated from these files: 8 | coprocess_common.proto 9 | coprocess_mini_request_object.proto 10 | coprocess_object.proto 11 | coprocess_return_overrides.proto 12 | coprocess_session_state.proto 13 | 14 | It has these top-level messages: 15 | StringSlice 16 | MiniRequestObject 17 | Object 18 | Event 19 | EventReply 20 | ReturnOverrides 21 | AccessSpec 22 | AccessDefinition 23 | BasicAuthData 24 | JWTData 25 | Monitor 26 | SessionState 27 | */ 28 | package coprocess 29 | 30 | import proto "github.com/golang/protobuf/proto" 31 | import fmt "fmt" 32 | import math "math" 33 | 34 | // Reference imports to suppress errors if they are not otherwise used. 35 | var _ = proto.Marshal 36 | var _ = fmt.Errorf 37 | var _ = math.Inf 38 | 39 | // This is a compile-time assertion to ensure that this generated file 40 | // is compatible with the proto package it is being compiled against. 41 | // A compilation error at this line likely means your copy of the 42 | // proto package needs to be updated. 43 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package 44 | 45 | type HookType int32 46 | 47 | const ( 48 | HookType_Unknown HookType = 0 49 | HookType_Pre HookType = 1 50 | HookType_Post HookType = 2 51 | HookType_PostKeyAuth HookType = 3 52 | HookType_CustomKeyCheck HookType = 4 53 | ) 54 | 55 | var HookType_name = map[int32]string{ 56 | 0: "Unknown", 57 | 1: "Pre", 58 | 2: "Post", 59 | 3: "PostKeyAuth", 60 | 4: "CustomKeyCheck", 61 | } 62 | var HookType_value = map[string]int32{ 63 | "Unknown": 0, 64 | "Pre": 1, 65 | "Post": 2, 66 | "PostKeyAuth": 3, 67 | "CustomKeyCheck": 4, 68 | } 69 | 70 | func (x HookType) String() string { 71 | return proto.EnumName(HookType_name, int32(x)) 72 | } 73 | func (HookType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } 74 | 75 | type StringSlice struct { 76 | Items []string `protobuf:"bytes,1,rep,name=items" json:"items,omitempty"` 77 | } 78 | 79 | func (m *StringSlice) Reset() { *m = StringSlice{} } 80 | func (m *StringSlice) String() string { return proto.CompactTextString(m) } 81 | func (*StringSlice) ProtoMessage() {} 82 | func (*StringSlice) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } 83 | 84 | func (m *StringSlice) GetItems() []string { 85 | if m != nil { 86 | return m.Items 87 | } 88 | return nil 89 | } 90 | 91 | func init() { 92 | proto.RegisterType((*StringSlice)(nil), "coprocess.StringSlice") 93 | proto.RegisterEnum("coprocess.HookType", HookType_name, HookType_value) 94 | } 95 | 96 | func init() { proto.RegisterFile("coprocess_common.proto", fileDescriptor0) } 97 | 98 | var fileDescriptor0 = []byte{ 99 | // 167 bytes of a gzipped FileDescriptorProto 100 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x3c, 0x8e, 0xb1, 0x0a, 0xc2, 0x30, 101 | 0x10, 0x40, 0xad, 0xad, 0xb6, 0xbd, 0x82, 0x86, 0x43, 0xc4, 0x51, 0x74, 0x11, 0x07, 0x17, 0xbf, 102 | 0x40, 0xba, 0x08, 0x1d, 0x2c, 0x56, 0x67, 0xc1, 0x70, 0xd8, 0x52, 0x93, 0x2b, 0x49, 0x8a, 0xe4, 103 | 0xef, 0x45, 0x05, 0xb7, 0xf7, 0xde, 0xf4, 0x60, 0x2e, 0xb9, 0x33, 0x2c, 0xc9, 0xda, 0x9b, 0x64, 104 | 0xa5, 0x58, 0xef, 0x3a, 0xc3, 0x8e, 0x31, 0xfd, 0xf7, 0xd5, 0x1a, 0xb2, 0xca, 0x99, 0x46, 0x3f, 105 | 0xaa, 0x67, 0x23, 0x09, 0x67, 0x30, 0x6a, 0x1c, 0x29, 0xbb, 0x08, 0x96, 0xe1, 0x26, 0x3d, 0xff, 106 | 0x64, 0x7b, 0x82, 0xe4, 0xc8, 0xdc, 0x5e, 0x7c, 0x47, 0x98, 0x41, 0x7c, 0xd5, 0xad, 0xe6, 0x97, 107 | 0x16, 0x03, 0x8c, 0x21, 0x2c, 0x0d, 0x89, 0x00, 0x13, 0x88, 0x4a, 0xb6, 0x4e, 0x0c, 0x71, 0x0a, 108 | 0xd9, 0x87, 0x0a, 0xf2, 0x87, 0xde, 0xd5, 0x22, 0x44, 0x84, 0x49, 0xde, 0x5b, 0xc7, 0xaa, 0x20, 109 | 0x9f, 0xd7, 0x24, 0x5b, 0x11, 0xdd, 0xc7, 0xdf, 0x8f, 0xfd, 0x3b, 0x00, 0x00, 0xff, 0xff, 0xbf, 110 | 0x7b, 0x4f, 0xde, 0xa1, 0x00, 0x00, 0x00, 111 | } 112 | -------------------------------------------------------------------------------- /mservclient/client/mserv_api_client.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-swagger; DO NOT EDIT. 2 | 3 | package client 4 | 5 | // This file was generated by the swagger tool. 6 | // Editing this file might prove futile when you re-run the swagger generate command 7 | 8 | import ( 9 | "github.com/go-openapi/runtime" 10 | httptransport "github.com/go-openapi/runtime/client" 11 | "github.com/go-openapi/strfmt" 12 | 13 | "github.com/TykTechnologies/mserv/mservclient/client/invocation" 14 | "github.com/TykTechnologies/mserv/mservclient/client/mw" 15 | "github.com/TykTechnologies/mserv/mservclient/client/system" 16 | ) 17 | 18 | // Default mserv API HTTP client. 19 | var Default = NewHTTPClient(nil) 20 | 21 | const ( 22 | // DefaultHost is the default Host 23 | // found in Meta (info) section of spec file 24 | DefaultHost string = "localhost:8989" 25 | // DefaultBasePath is the default BasePath 26 | // found in Meta (info) section of spec file 27 | DefaultBasePath string = "/" 28 | ) 29 | 30 | // DefaultSchemes are the default schemes found in Meta (info) section of spec file 31 | var DefaultSchemes = []string{"http", "https"} 32 | 33 | // NewHTTPClient creates a new mserv API HTTP client. 34 | func NewHTTPClient(formats strfmt.Registry) *MservAPI { 35 | return NewHTTPClientWithConfig(formats, nil) 36 | } 37 | 38 | // NewHTTPClientWithConfig creates a new mserv API HTTP client, 39 | // using a customizable transport config. 40 | func NewHTTPClientWithConfig(formats strfmt.Registry, cfg *TransportConfig) *MservAPI { 41 | // ensure nullable parameters have default 42 | if cfg == nil { 43 | cfg = DefaultTransportConfig() 44 | } 45 | 46 | // create transport and client 47 | transport := httptransport.New(cfg.Host, cfg.BasePath, cfg.Schemes) 48 | return New(transport, formats) 49 | } 50 | 51 | // New creates a new mserv API client 52 | func New(transport runtime.ClientTransport, formats strfmt.Registry) *MservAPI { 53 | // ensure nullable parameters have default 54 | if formats == nil { 55 | formats = strfmt.Default 56 | } 57 | 58 | cli := new(MservAPI) 59 | cli.Transport = transport 60 | cli.Invocation = invocation.New(transport, formats) 61 | cli.Mw = mw.New(transport, formats) 62 | cli.System = system.New(transport, formats) 63 | return cli 64 | } 65 | 66 | // DefaultTransportConfig creates a TransportConfig with the 67 | // default settings taken from the meta section of the spec file. 68 | func DefaultTransportConfig() *TransportConfig { 69 | return &TransportConfig{ 70 | Host: DefaultHost, 71 | BasePath: DefaultBasePath, 72 | Schemes: DefaultSchemes, 73 | } 74 | } 75 | 76 | // TransportConfig contains the transport related info, 77 | // found in the meta section of the spec file. 78 | type TransportConfig struct { 79 | Host string 80 | BasePath string 81 | Schemes []string 82 | } 83 | 84 | // WithHost overrides the default host, 85 | // provided by the meta section of the spec file. 86 | func (cfg *TransportConfig) WithHost(host string) *TransportConfig { 87 | cfg.Host = host 88 | return cfg 89 | } 90 | 91 | // WithBasePath overrides the default basePath, 92 | // provided by the meta section of the spec file. 93 | func (cfg *TransportConfig) WithBasePath(basePath string) *TransportConfig { 94 | cfg.BasePath = basePath 95 | return cfg 96 | } 97 | 98 | // WithSchemes overrides the default schemes, 99 | // provided by the meta section of the spec file. 100 | func (cfg *TransportConfig) WithSchemes(schemes []string) *TransportConfig { 101 | cfg.Schemes = schemes 102 | return cfg 103 | } 104 | 105 | // MservAPI is a client for mserv API 106 | type MservAPI struct { 107 | Invocation invocation.ClientService 108 | 109 | Mw mw.ClientService 110 | 111 | System system.ClientService 112 | 113 | Transport runtime.ClientTransport 114 | } 115 | 116 | // SetTransport changes the transport on the client and all its subresources 117 | func (c *MservAPI) SetTransport(transport runtime.ClientTransport) { 118 | c.Transport = transport 119 | c.Invocation.SetTransport(transport) 120 | c.Mw.SetTransport(transport) 121 | c.System.SetTransport(transport) 122 | } 123 | --------------------------------------------------------------------------------