├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── build.bat
├── build.sh
├── cert_file
├── ca.crt
├── ca.key
├── ca.srl
├── cert_file.go
├── client.crt
├── client.csr
├── client.key
├── server.crt
├── server.csr
└── server.key
├── conf
└── dev
│ ├── base.toml
│ ├── mysql_map.toml
│ ├── plugin_config.toml
│ ├── proxy.toml
│ └── redis_map.toml
├── control.sh
├── dashboard_controller
├── admin.go
├── admin_login.go
├── app.go
├── dashboard.go
├── oauth.go
└── service.go
├── dashboard_middleware
├── recovery.go
├── request_log.go
├── response.go
├── session_auth.go
└── translation.go
├── dashboard_router
├── httpserver.go
└── route.go
├── debug.sh
├── dist
├── favicon.ico
├── index.html
└── static
│ ├── css
│ ├── app.baa39a92.css
│ ├── chunk-1c7e619f.0be79fdd.css
│ ├── chunk-294e231b.d3b4ac8e.css
│ ├── chunk-2f5ea260.7777da69.css
│ ├── chunk-3f238847.a2fda0b3.css
│ ├── chunk-3f3d4b77.fe722f73.css
│ ├── chunk-4ce61457.41f5667e.css
│ ├── chunk-61ae4e7a.93d95231.css
│ ├── chunk-6525d41e.b1d9f1ec.css
│ ├── chunk-68b61de5.fb787c4e.css
│ ├── chunk-6f6c0d4e.c5f2d082.css
│ ├── chunk-80699a70.c0f8cc73.css
│ ├── chunk-bcebd8aa.78a33c26.css
│ ├── chunk-db410d48.50024827.css
│ ├── chunk-e9dba01a.b0fc6a10.css
│ └── chunk-libs.3dfb7769.css
│ ├── fonts
│ ├── element-icons.535877f5.woff
│ └── element-icons.732389de.ttf
│ ├── img
│ ├── 401.089007e7.gif
│ ├── 404.a57b6f31.png
│ ├── 404_cloud.0f4bc32b.png
│ ├── double-arrow-left.56942267.svg
│ └── logo.e3a14490.svg
│ └── js
│ ├── app.0f90f977.js
│ ├── chunk-1c7e619f.4dad2980.js
│ ├── chunk-294e231b.9c9d3bca.js
│ ├── chunk-2d230fe7.f069ed37.js
│ ├── chunk-2f5ea260.34edaec3.js
│ ├── chunk-3f238847.dde743ce.js
│ ├── chunk-3f3d4b77.f6066ce5.js
│ ├── chunk-4ce61457.350a970f.js
│ ├── chunk-57e15452.3a533841.js
│ ├── chunk-61ae4e7a.9dab1bdd.js
│ ├── chunk-6525d41e.3357aec3.js
│ ├── chunk-68b61de5.e515d0f3.js
│ ├── chunk-6f6c0d4e.3a34421a.js
│ ├── chunk-80699a70.d1cca3f7.js
│ ├── chunk-88ad1d84.14359848.js
│ ├── chunk-bcebd8aa.852867b4.js
│ ├── chunk-db410d48.75429a29.js
│ ├── chunk-e9dba01a.4f29b4df.js
│ ├── chunk-elementUI.1485574a.js
│ └── chunk-libs.16cb3d3b.js
├── dist_backup
├── favicon.ico
├── index.html
└── static
│ ├── css
│ ├── app.0eba9b7d.css
│ ├── chunk-294e231b.d3b4ac8e.css
│ ├── chunk-2f5ea260.7777da69.css
│ ├── chunk-335e7249.6d24dacd.css
│ ├── chunk-3f238847.a2fda0b3.css
│ ├── chunk-5c8c1f18.25617263.css
│ ├── chunk-61ae4e7a.93d95231.css
│ ├── chunk-6525d41e.b1d9f1ec.css
│ ├── chunk-68b61de5.fb787c4e.css
│ ├── chunk-6f6c0d4e.c5f2d082.css
│ ├── chunk-7be427f9.9fb4309b.css
│ ├── chunk-80699a70.c0f8cc73.css
│ ├── chunk-bcebd8aa.78a33c26.css
│ ├── chunk-e8029a4a.5c0a5547.css
│ ├── chunk-e9dba01a.b0fc6a10.css
│ └── chunk-libs.3dfb7769.css
│ ├── fonts
│ ├── element-icons.535877f5.woff
│ └── element-icons.732389de.ttf
│ ├── img
│ ├── 401.089007e7.gif
│ ├── 404.a57b6f31.png
│ ├── 404_cloud.0f4bc32b.png
│ ├── double-arrow-left.56942267.svg
│ └── logo.e3a14490.svg
│ └── js
│ ├── app.ded26861.js
│ ├── chunk-294e231b.9c9d3bca.js
│ ├── chunk-2d230fe7.f069ed37.js
│ ├── chunk-2f5ea260.34edaec3.js
│ ├── chunk-335e7249.8363c846.js
│ ├── chunk-3f238847.dde743ce.js
│ ├── chunk-57e15452.3a533841.js
│ ├── chunk-5c8c1f18.3f0435f6.js
│ ├── chunk-61ae4e7a.9dab1bdd.js
│ ├── chunk-6525d41e.3357aec3.js
│ ├── chunk-68b61de5.e515d0f3.js
│ ├── chunk-6f6c0d4e.3a34421a.js
│ ├── chunk-7be427f9.449b823a.js
│ ├── chunk-80699a70.d1cca3f7.js
│ ├── chunk-88ad1d84.14359848.js
│ ├── chunk-bcebd8aa.852867b4.js
│ ├── chunk-e8029a4a.619eb279.js
│ ├── chunk-e9dba01a.4f29b4df.js
│ ├── chunk-elementUI.1485574a.js
│ └── chunk-libs.16cb3d3b.js
├── docker_build.sh
├── dockerfile-dashboard
├── dockerfile-server
├── docs
├── docs.go
├── swagger.json
└── swagger.yaml
├── favicon.ico
├── gatekeeper.sql
├── go.mod
├── go.sum
├── golang_common
├── lib
│ ├── cmd.go
│ ├── conf.go
│ ├── func.go
│ ├── log.go
│ ├── mysql.go
│ ├── redis.go
│ └── request.go
├── trace
│ ├── trace.go
│ └── trace_test.go
└── zerolog
│ ├── .gitignore
│ ├── CNAME
│ ├── LICENSE
│ ├── _config.yml
│ ├── access_write.go
│ ├── array.go
│ ├── array_json.go
│ ├── array_json_test.go
│ ├── array_test.go
│ ├── benchmark_json_test.go
│ ├── binary_json_test.go
│ ├── binary_test.go
│ ├── cmd
│ └── lint
│ │ ├── lint.go
│ │ └── readme.md
│ ├── console.go
│ ├── console_test.go
│ ├── context.go
│ ├── ctx.go
│ ├── ctx_test.go
│ ├── ddlog
│ ├── ddlog.go
│ ├── init.go
│ └── log.go
│ ├── diode
│ ├── diode.go
│ ├── diode_example_test.go
│ ├── diode_test.go
│ └── internal
│ │ └── diodes
│ │ ├── README
│ │ ├── many_to_one.go
│ │ ├── one_to_one.go
│ │ ├── poller.go
│ │ └── waiter.go
│ ├── elevate
│ └── cr.yml
│ ├── encoder.go
│ ├── encoder_cbor.go
│ ├── encoder_console.go
│ ├── encoder_json.go
│ ├── event.go
│ ├── event_json.go
│ ├── fields.go
│ ├── file_write.go
│ ├── globals.go
│ ├── hlog
│ ├── hlog.go
│ ├── hlog_example_test.go
│ └── hlog_test.go
│ ├── hook.go
│ ├── hook_test.go
│ ├── internal
│ ├── cbor
│ │ ├── README.md
│ │ ├── base.go
│ │ ├── cbor.go
│ │ ├── decode_stream.go
│ │ ├── decoder_test.go
│ │ ├── examples
│ │ │ ├── genLog.go
│ │ │ └── makefile
│ │ ├── string.go
│ │ ├── string_test.go
│ │ ├── time.go
│ │ ├── time_test.go
│ │ ├── types.go
│ │ └── types_test.go
│ ├── console
│ │ ├── base.go
│ │ ├── bytes.go
│ │ ├── string.go
│ │ ├── time.go
│ │ └── types.go
│ ├── json
│ │ ├── base.go
│ │ ├── bytes.go
│ │ ├── bytes_test.go
│ │ ├── string.go
│ │ ├── string_test.go
│ │ ├── time.go
│ │ ├── types.go
│ │ └── types_test.go
│ └── ordered
│ │ └── ordered.go
│ ├── journald
│ ├── journald.go
│ └── journald_test.go
│ ├── log.go
│ ├── log
│ ├── log.go
│ └── log_example_test.go
│ ├── log_example_test.go
│ ├── log_json_example_test.go
│ ├── log_json_test.go
│ ├── log_test.go
│ ├── pretty.png
│ ├── sampler.go
│ ├── sampler_test.go
│ ├── stdout_write.go
│ ├── syslog.go
│ ├── syslog_json_test.go
│ ├── syslog_test.go
│ ├── utils.go
│ ├── wfwriter.go
│ ├── writer.go
│ ├── writer_json_test.go
│ └── writer_test.go
├── grpc_proxy_middleware
├── grpc_black_list.go
├── grpc_flow_count.go
├── grpc_flow_limit.go
├── grpc_jwt_auth_token.go
├── grpc_jwt_flow_count.go
├── grpc_jwt_flow_limit.go
├── grpc_metadata_transfer.go
├── grpc_test.go
└── grpc_white_list.go
├── grpc_proxy_router
└── grpcserver.go
├── handler
├── app_count_handler.go
├── app_manager_handler.go
├── distributed_count_handler.go
├── distributed_limit_handler.go
├── limit_handler.go
├── load_balancer_handler.go
├── service_count_handler.go
├── service_manager_handler.go
└── transporter_handler.go
├── http_proxy_middleware
├── http_access_mode.go
├── http_black_list.go
├── http_flow_count.go
├── http_flow_limit.go
├── http_header_transfer.go
├── http_jwt_auth_token.go
├── http_jwt_flow_count.go
├── http_jwt_flow_limit.go
├── http_recovery.go
├── http_request_log.go
├── http_reverse_proxy.go
├── http_strip_uri.go
├── http_translation.go
├── http_url_rewrite.go
└── http_white_list.go
├── http_proxy_router
├── httpserver.go
└── route.go
├── install
├── build.bat
├── build.sh
├── check
│ ├── conf.go
│ ├── gateway.go
│ ├── mysql.go
│ ├── path.go
│ └── redis.go
├── go.mod
├── go.sum
├── install.sh
├── main.go
├── template
│ ├── conf.go
│ └── mysql.go
└── tool
│ ├── log.go
│ ├── reader.go
│ ├── system.go
│ └── zip.go
├── k8s_dashboard.yaml
├── k8s_server.yaml
├── load_balance
├── consistent_hash_strategy.go
├── consistent_hash_strategy_test.go
├── loadbalance_check_config.go
├── loadbalance_config.go
├── loadbalance_config_test.go
├── loadbalance_strategy.go
├── random_strategy.go
├── random_strategy_test.go
├── round_robin_strategy.go
├── round_robin_strategy_test.go
├── weight_round_strategy.go
└── weight_round_strategy_test.go
├── main.go
├── model
├── admin_dto.go
├── admin_login_dto.go
├── admin_model.go
├── app_dto.go
├── app_model.go
├── dashboard_dto.go
├── oauth_dto.go
├── plugin_config.go
├── service_detail_model.go
├── service_dto.go
└── service_info_model.go
├── public
├── const.go
├── http_response.go
├── jwt.go
├── log.go
├── params.go
├── redis.go
└── util.go
├── reverse_proxy
├── grcp_reverse_proxy.go
├── http_reverse_proxy.go
└── tcp_reverse_proxy.go
├── setup.sh
├── tcp_proxy_middleware
├── tcp_black_list.go
├── tcp_flow_count.go
├── tcp_flow_limit.go
├── tcp_slice_router.go
└── tcp_white_list.go
├── tcp_proxy_router
└── tcpserver.go
├── tcp_server
├── tcp_conn.go
└── tcp_server.go
└── test_suites
├── README.md
├── SqlHandler
└── service_info_model.go
├── cert_file
├── ca.crt
├── ca.key
├── ca.srl
├── cert_file.go
├── client.crt
├── client.csr
├── client.key
├── server.crt
├── server.csr
└── server.key
├── conf
├── base.toml
├── mysql_map.toml
├── plugin_config.toml
├── proxy.toml
└── redis_map.toml
├── gatekeeper_test.sql
├── goconvey.sh
├── goconvey_shell.sh
├── run_test.go
├── test_case.go
├── test_httpserver.sh
├── test_rpcserver.sh
├── testhttp
├── main
│ └── main.go
└── test_server.go
└── testrpc
├── main
└── main.go
├── thrift_gen.thrift
├── thriftclient
└── main.go
├── thriftgen
├── thrift_gen-consts.go
└── thrift_gen.go
└── thriftserver
└── server.go
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .idea/
3 | logs/
4 | bin/
5 | build/
6 | onekeyupdate.sh
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contribution Guideline
2 |
3 | Thanks for considering to contribute this project. All issues and pull requests are highly appreciated.
4 |
5 | ## Pull Requests
6 |
7 | Before sending pull request to this project, please read and follow guidelines below.
8 |
9 | 1. Branch: We only accept pull request on `master` branch.
10 | 2. Coding style: Follow the coding style used in Go.
11 | 3. Commit message: Use English and be aware of your spell.
12 | 4. Test: Make sure to test your code.
13 |
14 | Add device mode, API version, related log, screenshots and other related information in your pull request if possible.
15 |
16 | NOTE: We assume all your contribution can be licensed under the [Apache License 2.0](LICENSE).
17 |
18 | ## Issues
19 |
20 | We love clearly described issues. :)
21 |
22 | Following information can help us to resolve the issue faster.
23 |
24 | * Device mode and hardware information.
25 | * API version.
26 | * Logs.
27 | * Screenshots.
28 | * Steps to reproduce the issue.
29 |
--------------------------------------------------------------------------------
/build.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | color 0d
3 |
4 | echo =================================
5 | echo ==========Build Linux ======
6 | echo =================================
7 | SET CGO_ENABLED=0
8 | SET GOOS=linux
9 | SET GOARCH=amd64
10 | echo now the CGO_ENABLED:
11 | go env CGO_ENABLED
12 | echo now the GOOS:
13 | go env GOOS
14 | echo now the GOARCH:
15 | go env GOARCH
16 | go build -o bin/gatekeeper_linux main.go
17 |
18 | echo =================================
19 | echo ==========Build Mac ======
20 | echo =================================
21 | SET CGO_ENABLED=0
22 | SET GOOS=darwin
23 | SET GOARCH=amd64
24 | echo now the CGO_ENABLED:
25 | go env CGO_ENABLED
26 | echo now the GOOS:
27 | go env GOOS
28 | echo now the GOARCH:
29 | go env GOARCH
30 | go build -o bin/gatekeeper_mac main.go
31 |
32 | echo =================================
33 | echo ==========Build Windows ======
34 | echo =================================
35 | SET CGO_ENABLED=1
36 | SET GOOS=windows
37 | SET GOARCH=amd64
38 | echo now the CGO_ENABLED:
39 | go env CGO_ENABLED
40 | echo now the GOOS:
41 | go env GOOS
42 | echo now the GOARCH:
43 | go env GOARCH
44 | go build -o bin/gatekeeper_windows.exe main.go
45 |
46 |
47 |
--------------------------------------------------------------------------------
/cert_file/ca.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDATCCAemgAwIBAgIJAKCCwAOLbkgiMA0GCSqGSIb3DQEBCwUAMBcxFTATBgNV
3 | BAMMDGV4YW1wbGUxLmNvbTAeFw0yMDAzMzExNTQzMzZaFw0zMzEyMDgxNTQzMzZa
4 | MBcxFTATBgNVBAMMDGV4YW1wbGUxLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP
5 | ADCCAQoCggEBAK0bl7z0oPQYOj2XSiFljYifyzReev77cmYfGg+GQF3WZqIbYppD
6 | ajMi88gOidfcUDZGQI/tPgO8tB5M5TetP/q+apSu6VK7fMpeia417VBvL9T05yCK
7 | R9ylqDzg+he4DFxdruIu8Q4MhhFNoPSw4DGoNYjQw76UFu1x2h4X01MFm9sJ3hhG
8 | LmcTUb27p3EEbi2s/8TZVsTIuBF6GeJrNxDMBRRvgOm4/NCSWQSVPGGOdYJroQJG
9 | FKxSHb+VjAh1GfSD4np7lTgfMGlLvhTt1meynEUYorV15xnoyeD077NM0OX2JG0Z
10 | 1HbBUqVd2EO4WFX3kXZDGBB8C3wPg2zYtCUCAwEAAaNQME4wHQYDVR0OBBYEFMOA
11 | FTyjXBBcvO0Z5nY34ITA/vwZMB8GA1UdIwQYMBaAFMOAFTyjXBBcvO0Z5nY34ITA
12 | /vwZMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAG/kIiQalUfXPT4/
13 | QQAMk6msDETY9wEDwnTIsHyXQlZiKxroIgplDHuhlVjRww2Fa0JHqXuRpIJN9UR1
14 | mLZubn3oCMk/hWkgfb714f3/YFho4vyjzfMQ8rwCwrD/r3ZnlMSj39a7bTA7YKW4
15 | Hni4fooM/ny//c+xXeif64yTkmsYCqxSwtVZLvCRJMxfrbgo3f7ILn5rTB7hsUfG
16 | tcwu4g8bNkFnXrVGS1OLBNd53jDDSmPs1pdx9jekR3o8l7Sr5BPo3C/CPOiXdfjJ
17 | Tqm+I2wo6pr/SKbZsslxajGBXjSwhjgkjYRBCLu7wxCJsbxHnl5ORs6O7eoINpcM
18 | e6JTUfY=
19 | -----END CERTIFICATE-----
20 |
--------------------------------------------------------------------------------
/cert_file/ca.key:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIEowIBAAKCAQEArRuXvPSg9Bg6PZdKIWWNiJ/LNF56/vtyZh8aD4ZAXdZmohti
3 | mkNqMyLzyA6J19xQNkZAj+0+A7y0HkzlN60/+r5qlK7pUrt8yl6JrjXtUG8v1PTn
4 | IIpH3KWoPOD6F7gMXF2u4i7xDgyGEU2g9LDgMag1iNDDvpQW7XHaHhfTUwWb2wne
5 | GEYuZxNRvbuncQRuLaz/xNlWxMi4EXoZ4ms3EMwFFG+A6bj80JJZBJU8YY51gmuh
6 | AkYUrFIdv5WMCHUZ9IPienuVOB8waUu+FO3WZ7KcRRiitXXnGejJ4PTvs0zQ5fYk
7 | bRnUdsFSpV3YQ7hYVfeRdkMYEHwLfA+DbNi0JQIDAQABAoIBABSNcx2PGdEBU2De
8 | poGCkiRHfJPSJ95AMlvnk2uGb/v0KalTgQh5upEptDHrb/g+AxP+kUnFTBibffMf
9 | BBPxMOhvVS4j+jXFZtKMGOKjKnLjUJWDIjHd2RxcWrYnq+nHA0iwIsRd+GbHm99Q
10 | DS0gFu4uX3TH/IWTBYnZe6EZCRERJmoL3T8oIqW9V8M3lszoQ8UormPAXIH3g+k2
11 | 3L3Dy/Eo8IxoFmsYiCWf8ec16lCyOTS9zLvdNGK26SGU7J/w7x7fhqlZ6zLS97lH
12 | KMgVQtoZWz7S9NrrMRpdDbdgz/KVnm465o7E+X2PuwjJsyG3gCjrsNgq4wJgfZzF
13 | QJmE48ECgYEA1lrLUg2hebSaBHbnYKphpEd9jGA1FMDl6S93kwZvQKUhqEBlK5gv
14 | Ty+4R+/Pvc0qtAj+bLwrL8fFwQ0l3sXtpGbpt1jPVO87ui5ikP0Orfc300asjtp2
15 | JViYgaHHW4phWmlqtQGswaXsDFx608a/OrFw3IwlKDUzGtOEb+b6u/ECgYEAzr1U
16 | 6OtgDHKD6YlPUwgSujENadZ0BFk6wW91DjEldb9eXycgYenWKg2vJZskylRpvzSQ
17 | uKTtQLAxj7WxCymrtrPpA4XvWbFG3p2mSYLt1XO63UE0MJ1f5FDBW/Co4TM7YMbs
18 | Eknqapwm4ahOtDrSbb3uL95yMJBBRkpJjxKIv3UCgYAxxVkqTzHsIWwVl0o4HreX
19 | PmY/XuNUU0nO8A+Sms7gMrdy6qjTC34Io+rlASC6UFYXAXOZ6cMZUAhxv8zIQirg
20 | nmisArn5Xab/nt+SDMAI0rsqmmFctgrytvSKPPceIS5joNB/AMmNGSqK4DpAzAgA
21 | 58xt2TiTcm7QTsaUeQxE8QKBgQCPFk1hVB9LHischLOJRUoo4fBls07i/5sB7JF4
22 | vB0wLL41X1AzVHOs8YGqpoFFJD14X/pWQZgPsKLs0xTxI+s77bM1hAqP6nmhdD12
23 | HY9cr9fCcPGdQB7xV88sQhmwnBPZvHQBiHUdSmxCvImUhi3EVLM5IF2qLP1wl9Pn
24 | mS1aTQKBgDkTOc3Sod1Zj42MBvJQO8uDAjwx/CJDKEh1v2v1roOt0m2H/peJJ9HY
25 | SXB/fk3oXnUyKn23jl9HOwEgArHGTxwnorH7VVOjN8PA5VyPnZzbyRCbo4P24mNT
26 | 5GJjUyHXtAKfYn/vL4XneNo8htRmgO/buDA9Mz03LGFZjHn+/sB7
27 | -----END RSA PRIVATE KEY-----
28 |
--------------------------------------------------------------------------------
/cert_file/ca.srl:
--------------------------------------------------------------------------------
1 | EB10040B98B12C16
2 |
--------------------------------------------------------------------------------
/cert_file/cert_file.go:
--------------------------------------------------------------------------------
1 | package cert_file
2 |
3 | import (
4 | "path/filepath"
5 | "runtime"
6 | )
7 |
8 | // basepath is the root directory of this package.
9 | var basepath string
10 |
11 | func init() {
12 | _, currentFile, _, _ := runtime.Caller(0)
13 | basepath = filepath.Dir(currentFile)
14 | }
15 |
16 | func Path(rel string) string {
17 | if filepath.IsAbs(rel) {
18 | return rel
19 | }
20 |
21 | return filepath.Join(basepath, rel)
22 | }
23 |
--------------------------------------------------------------------------------
/cert_file/client.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIICqjCCAZICCQDrEAQLmLEsFTANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxl
3 | eGFtcGxlMS5jb20wHhcNMjAwMzI5MTMxNTQyWhcNMzMxMjA2MTMxNTQyWjAXMRUw
4 | EwYDVQQDDAxleGFtcGxlMS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
5 | AoIBAQDmMVbGx9gdqb3l+WcQAVht5YvIfPhrUx8/PjZ8XUFwqIt8s4JJcmCoYrpi
6 | QwYjckajLNEfeovieFPlx1EpDbMa9C3QFeuqCI453w2InAEiCU6VGKqftSy/OQM0
7 | 19fNOX7ec9uB+64AjifSkyjr3GnmJjSHZS8XczKZk4XZV8vA1oUwMvW7shbDL8ar
8 | Qw7MEALFzCFgz7Ff5/Hfpm0gHY0A2ychUTn/w6zB/fTTV5+kYtZNnmFP5zPBdOVX
9 | soNYRY3GXGRAvoJy3o9tzPWetL/0Uzjmc1HU+kHVp2vVhyfsuZldHxgTY9KRA22m
10 | /5jdVPJX5Z4UBEaW5+hrhh8T6BQJAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAETU
11 | I5Tkek8W+I86arMmswXTm+/CsJdpoXAm3xuhXoUQo7QfZI0lQ/vbsSMc26GUn8ho
12 | NLMJvBv31QYIq39dQypFKAloA9mml91jUwMno9L0nsEyYMXcFaUvs2YE5v2RZghN
13 | j86FBGOt0Ou3UDGhvzbQUvIS53gurCavDCFSHVuFxKeLhyVRCoESWClRX426mVv7
14 | lPfHXfAIOs0yZxvxRA/fVokGfqhmTjPIeLPuDTxoR4uVqV/kRJ7tb6mrNAGVhDZJ
15 | BzrhvZ8DbF56sImetftbkMdzIumddy2H3emd8syEf+zy8LLMfXnLS9QXkFD2+RRJ
16 | EaC4UfgFTEcvooUO6/s=
17 | -----END CERTIFICATE-----
18 |
--------------------------------------------------------------------------------
/cert_file/client.csr:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE REQUEST-----
2 | MIICXDCCAUQCAQAwFzEVMBMGA1UEAwwMZXhhbXBsZTEuY29tMIIBIjANBgkqhkiG
3 | 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5jFWxsfYHam95flnEAFYbeWLyHz4a1MfPz42
4 | fF1BcKiLfLOCSXJgqGK6YkMGI3JGoyzRH3qL4nhT5cdRKQ2zGvQt0BXrqgiOOd8N
5 | iJwBIglOlRiqn7UsvzkDNNfXzTl+3nPbgfuuAI4n0pMo69xp5iY0h2UvF3MymZOF
6 | 2VfLwNaFMDL1u7IWwy/Gq0MOzBACxcwhYM+xX+fx36ZtIB2NANsnIVE5/8Oswf30
7 | 01efpGLWTZ5hT+czwXTlV7KDWEWNxlxkQL6Cct6Pbcz1nrS/9FM45nNR1PpB1adr
8 | 1Ycn7LmZXR8YE2PSkQNtpv+Y3VTyV+WeFARGlufoa4YfE+gUCQIDAQABoAAwDQYJ
9 | KoZIhvcNAQELBQADggEBALEp4ePq57a+XRa7GSS6WUMX5HibHNSqy1VrA5h8LdTP
10 | zFv8ZnasuCgWh3Z7w7j8TeBgygO4wwldbafdXS234rzYas5wXlVFW7tY4jX/jCDy
11 | 7ftypbYGnKCMScQ34FKRB2WOZvWEdMYN5i8EyKaBy0Bitc+kZ+yCGSNH57QptOgR
12 | oRMK/r6Z+TGucF6EpLhxgOknUCitGme9FP96A6gs3lLrPQ1yOYE456ubTzq6svVo
13 | 5viGzSZwADzGzBNQ0GDr7Fv9boLEKyK+wCB+8us0PDVDid9ryIokjxT+Ddnv19MS
14 | fEL9GdJTyQCu/JWWynQgh1t5uF4vyUgi6wlU8Ermjnw=
15 | -----END CERTIFICATE REQUEST-----
16 |
--------------------------------------------------------------------------------
/cert_file/client.key:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIEpQIBAAKCAQEA5jFWxsfYHam95flnEAFYbeWLyHz4a1MfPz42fF1BcKiLfLOC
3 | SXJgqGK6YkMGI3JGoyzRH3qL4nhT5cdRKQ2zGvQt0BXrqgiOOd8NiJwBIglOlRiq
4 | n7UsvzkDNNfXzTl+3nPbgfuuAI4n0pMo69xp5iY0h2UvF3MymZOF2VfLwNaFMDL1
5 | u7IWwy/Gq0MOzBACxcwhYM+xX+fx36ZtIB2NANsnIVE5/8Oswf3001efpGLWTZ5h
6 | T+czwXTlV7KDWEWNxlxkQL6Cct6Pbcz1nrS/9FM45nNR1PpB1adr1Ycn7LmZXR8Y
7 | E2PSkQNtpv+Y3VTyV+WeFARGlufoa4YfE+gUCQIDAQABAoIBAQDh1I/EjnTIjSl/
8 | QBHLUvaVQjjDpU71w+OI4RkFI1w7ES9fVKDCO5L2P32JPyX7inYgSayUDF7F/LSa
9 | XdOSyhznmZyEY60C8EfQILMfTaWS5byRa1ShQFY4987cfdD6RqjfxpwYRnirlMse
10 | vD7OPjwqjVrFZhAwGlUO8/rBgm+jqzUWL4aGoGuH2M/6XP6rUN42GFrLxQnshxpq
11 | CiGTnyB1nYYdQKSEWSBoEthQKNXR/MyTQDHt05EpAu8TQFGi/oXytFzu6LlVlQVB
12 | OdfDAXDcLqF1VyEndjdCNp8i8jWVdvNuHCm/dw2v286HADq8ZnaspG6ghxvegHSF
13 | CPWlAvdxAoGBAPnd2UWFpo95EdvsDo2MKkgJRmqyjx2kkUPjClgZgz6sfrjufV71
14 | Axonj8SCM4QmnjvZN8tdjKc7N1xYOShDAlIUkuAKNw/uxyzuj98Fi5SwEfCrCowT
15 | MlJEliRFcRhSDKJdUwhz+gX3f/SFHLUOT8S2VR3kssesklznB0k9R6CtAoGBAOvX
16 | 3EmZd4vDijDLmZ5hz5fmsI9/LYrDSzd5+D0nYHrt0l81Yn69T4TNU6pau3Qv6ZET
17 | 5PyDiuDSTi2XLV3TPgeGqimU6E3MzH2ZX69Sqz74JNSrOj2xmiLTHpjFLx2HgYBo
18 | 2r/4qaX3UbeLosU+OAgTZz7tAUu8oKaVNWAMp8BNAoGBAMrF+CoMUWRDq3OfORwz
19 | 8KgvJr82EyDKSb0fBmkCo1j8YYawvHuQOKlEC888npQTRvxoxne6fofEbaP6UMBU
20 | yRBVc/BvOcorS+Yx3/3soR7UWGrIU7HjbkYHNRVQaXyEMY6eT+EfRXsMJQIJ+IcS
21 | izenhKHS1Cdo7AqKzoXoPjWtAoGBAOY6toBewZX90GRsDU3Q/B+0gv3CUEoa9c11
22 | UwEX9JZsnaZ17e39jqf87UTrB/2XXDJVMn/TRfrNMqZM42upcO9V5b1r8Q8p8yJV
23 | XFRBpox1HzdA5D0fqHGAmWjXbXQtOR2KvqkS7UHoWqyMMtzMLVSs5GhIY7B0tnuI
24 | Qy+9ivEtAoGAdvwxqztV2UTTszPhBZZ5rWhMB1W4DAW4SkqVtChsaVgjPO+w1RCz
25 | sRauu3pewdyhseOouDvGB7nRdozfusr8gE1qimj7T+bvBAz67jfLdjIB/EWt73UM
26 | rypIzF6D7FQMx1FTD1VDBqE3dmkDbTj6A3vrcv9FrqqS+IirNlbwdbk=
27 | -----END RSA PRIVATE KEY-----
28 |
--------------------------------------------------------------------------------
/cert_file/server.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIICqjCCAZICCQDrEAQLmLEsFjANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxl
3 | eGFtcGxlMS5jb20wHhcNMjAwMzMxMTU0NTA5WhcNMzMxMjA4MTU0NTA5WjAXMRUw
4 | EwYDVQQDDAxleGFtcGxlMS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
5 | AoIBAQDMfuI0VxqOmpgFa65BMa6pv5rYYLLAVuQeGNPbl19sZeSNlfR0Zupk2jmg
6 | MTK4F6R77bCpv3505txFxFxn8vFVJcOSDwpZCCl0iTI9jZoYugYh2Mk2bslHCxV0
7 | k/yzVhCCIvxeKFb3/XSUSu4YZ76D9PmqSxGUqKUqXv5lgI3QWDMO3/CwWP6I0SWv
8 | tyxB63mM3UfjfHw301syvJuPxWfAMdCHnxiAa8RlLcoKMawMQUyZqOP5dHmL565V
9 | izHDbrB+B2D2gznoazV95rW7adlpf9cIsQI30ExksL+FnDcmlsChpjooHLJGF8Wg
10 | XZNU1RTfp9oOpA7/K0ul5D9BYGgfAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAAXt
11 | FToCcyVURZXKNDKJEw8qHMJshwygtHnnxrZtioGuy2T767PAMWoi7yrv4WSRGnWn
12 | lhM6nx3iUBDRJ7UNEbn3bOQJm5kAVGTb+/dB7rm7slwsQ6Es2Tl+cnr9ySruIs0s
13 | jPRr48ufD3C1275d7KhDXXT2l9un+w5G8a55EfXt5qN5tQByR5jNNsSkYnBhtrbk
14 | VvjSpTm4n98qI3PfMd4JyAJjkxm/qvgeCS6XZS7LdTwf5LTOaEg/+0BZ0KoQC0uu
15 | C35qUJv3hUEXm3bUz/HD2CrFloskD+jcnLcqIWjQ79uFfgJVH4fH+Tl1P+/+N0zp
16 | TEGij1GvoSfrnq30qpc=
17 | -----END CERTIFICATE-----
18 |
--------------------------------------------------------------------------------
/cert_file/server.csr:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE REQUEST-----
2 | MIICXDCCAUQCAQAwFzEVMBMGA1UEAwwMZXhhbXBsZTEuY29tMIIBIjANBgkqhkiG
3 | 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzH7iNFcajpqYBWuuQTGuqb+a2GCywFbkHhjT
4 | 25dfbGXkjZX0dGbqZNo5oDEyuBeke+2wqb9+dObcRcRcZ/LxVSXDkg8KWQgpdIky
5 | PY2aGLoGIdjJNm7JRwsVdJP8s1YQgiL8XihW9/10lEruGGe+g/T5qksRlKilKl7+
6 | ZYCN0FgzDt/wsFj+iNElr7csQet5jN1H43x8N9NbMrybj8VnwDHQh58YgGvEZS3K
7 | CjGsDEFMmajj+XR5i+euVYsxw26wfgdg9oM56Gs1fea1u2nZaX/XCLECN9BMZLC/
8 | hZw3JpbAoaY6KByyRhfFoF2TVNUU36faDqQO/ytLpeQ/QWBoHwIDAQABoAAwDQYJ
9 | KoZIhvcNAQELBQADggEBAGL7N5UnX0K1i0OH+dJmTR2o14qFoub/eb3vXFZmLdmS
10 | KIR3eHBfnQPLwD6cOaoQiOZgBXOLjbV3lXyogDETUtRxBx+8nb4AX63oPyiHCu3M
11 | htJlxvB1tLZRvWePqypKNZ8hJy8c9c71ZvZggj7uzTT/yupjbs/u1s64NSGtEjio
12 | jXhlxOcClqn0NGIzVyyByVKTFCmOqNKBz5ohqCN78DnxRwzB8SOMLT9gzzXemVXg
13 | vOtctJo55KG6D35Ra5I6FVU68851W8o0FQy9Il+2GrbL0Lw8NpEbbGnfbD65fkKZ
14 | 33xk9GCEWmCYtL7XkCV1cvRWgKGrmoBK9LsScbH0O2A=
15 | -----END CERTIFICATE REQUEST-----
16 |
--------------------------------------------------------------------------------
/cert_file/server.key:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIEowIBAAKCAQEAzH7iNFcajpqYBWuuQTGuqb+a2GCywFbkHhjT25dfbGXkjZX0
3 | dGbqZNo5oDEyuBeke+2wqb9+dObcRcRcZ/LxVSXDkg8KWQgpdIkyPY2aGLoGIdjJ
4 | Nm7JRwsVdJP8s1YQgiL8XihW9/10lEruGGe+g/T5qksRlKilKl7+ZYCN0FgzDt/w
5 | sFj+iNElr7csQet5jN1H43x8N9NbMrybj8VnwDHQh58YgGvEZS3KCjGsDEFMmajj
6 | +XR5i+euVYsxw26wfgdg9oM56Gs1fea1u2nZaX/XCLECN9BMZLC/hZw3JpbAoaY6
7 | KByyRhfFoF2TVNUU36faDqQO/ytLpeQ/QWBoHwIDAQABAoIBABMQqUoz7Lfq1c17
8 | ko1lcmFFCcyuhzvDXhUoP2gznqPehAZnOpk3lxa7+a9jptTe72jWaigJQGLpuxOO
9 | EQdn8PP9R1RwrohKaIMC33o5n2o6vaOeMHQws/c5o1BxE5gsp/FaDalBnYoVSS8i
10 | JTyFP4/R4QztXsA7UNq4bINODuqjg8O6Fc7AQhXLOe7It8rQxbuNKF0Pps2RwzEL
11 | yTS1Ehi3Rujhb/uBVEnzYZluhylYUZJ2sE7SijNxHGp9sHe6l/YkKC1GLf+7SxvA
12 | 3vWC4SU/REnCbfpUKkm8eV2276frvvY9IJSgWaINLOnRrFKfYTEvuuIBm5Bav5Sl
13 | 1htTUBECgYEA6L+bwhLy5RD38xjuAIt4a1E7KIU5cDA/a8DUM5rTN3IZqlkbprRl
14 | wSe9MzsudFQd33qzyJXalhvWevrJiycOc3pZ92KDd5cnsh5a+JQkOO68evxyrPpx
15 | +d7+K31fu0qBBxfO26RPMGLOL/7CXfVBOeJZAWH0lO+uI5n8Aphv2TsCgYEA4Oy6
16 | MBaRDWYyM5gZbJdWSk1G9HR3rV8fQgjz9aMQksaJdV0Bm1IgqzMQEuDFr43tK89s
17 | UV/2W4ULl5esKJq9RBs4KsERIrARXgooU2Kw3A3PRzkg7mOS68qL/ESOtxF9F+UC
18 | PSyH8ehdfN6WAdNlxloIXsLJjkHWfJ9/ivYkHm0CgYA2T8gL8JoHg/8oFhArxl/y
19 | QwFYAkaV/FxAS7340M8q6BA/JQ4Dx6LbAOfwlYXQlXRnGt3rF7TrRFG3XuA6/YEs
20 | x0dJKA7fkEEuGlFGImOVeXg4BsLHxKVmFngfM+Fr9gXH3vFhZaUo+FV+86btf/aZ
21 | iE0WuoH1YzyyiBM7k9C90wKBgQDFYDcKl+L15SZMjD5TQoJgdWu8fK/AneZqJj0e
22 | 4tdaVYquSM1uJSWx1f9W8ZPIOD1V4pFk31bqfNftURWsFA3eRByHuCB3VhYHddZp
23 | RgN5N00bbRBu4UY+T+GDoA20rE4ft8C9OeSZ7ZSMTS9Jrt5yrvMFZN1GTpQPjE95
24 | /AE6CQKBgDEmZCoZt8vgzqWjsylzuQpx2gWnZT+5rXi3gOGZmzvqdZdOloZqxgVs
25 | EdCP2ZMcwcXecsraoEjdLMCjRVlgw1cCd+ag4yX93FQTcqClx8oqSBSpcoAab7xo
26 | COBb/9wUo4Dl7JztpX3UJacEf0QQpMUcfUAvs+w3rDkRlu0QeLz/
27 | -----END RSA PRIVATE KEY-----
28 |
--------------------------------------------------------------------------------
/conf/dev/base.toml:
--------------------------------------------------------------------------------
1 | # This is base config
2 | [base]
3 | debug_mode="release"
4 | time_location="Asia/Chongqing"
5 | ser_name="gatekeeper"
6 |
7 | [http]
8 | addr =":8880" # 监听地址, default ":8700"
9 | read_timeout = 10 # 建立连接到读取请求内容超时时间
10 | write_timeout = 10 # 读取内容到响应的超时时间
11 | max_header_bytes = 20 # 最大的header大小,二进制位长度
12 | allow_ip = [ # 白名单ip列表
13 | "127.0.0.1",
14 | "192.168.1.1"
15 | ]
16 |
17 | [pprof]
18 |
19 | [log]
20 | on = true #日志开关,是否开启
21 | level = "info" #日志级别,只支持小写
22 | file_prefix = "didi" #文件名前缀, 默认会加后缀.log 或者.log.wf
23 | file_dir = "logs" #生成文件目录
24 | auto_clear = false #是否自动清理日志
25 | clear_hours = 3 #保留日志 n 个小时的
26 | clear_step = 3 #清理时间从当前时间前推 n 个小时算起
27 | separate = false #文件是否分离,分离文件以.wf结尾
28 | disable_link = false #是否启动link
29 |
30 | [cluster]
31 | cluster_ip="127.0.0.1"
32 | cluster_port="8080"
33 | cluster_ssl_port="4433"
34 |
35 | [swagger]
36 | title="gatekeeper swagger API"
37 | desc="This is a sample server celler server."
38 | host=""
39 | base_path=""
--------------------------------------------------------------------------------
/conf/dev/mysql_map.toml:
--------------------------------------------------------------------------------
1 | # this is mysql config
2 | [list]
3 | [list.default]
4 | driver_name = "mysql"
5 | data_source_name = "root:123456@tcp(127.0.0.1:3306)/gatekeeper?charset=utf8&parseTime=true&loc=Asia%2FChongqing"
6 | max_open_conn = 20
7 | max_idle_conn = 10
8 | max_conn_life_time = 100
--------------------------------------------------------------------------------
/conf/dev/proxy.toml:
--------------------------------------------------------------------------------
1 | # This is base config
2 |
3 | [base]
4 | debug_mode="release"
5 | time_location="Asia/Chongqing"
6 |
7 | [http]
8 | addr =":8080" # 监听地址, default ":8700"
9 | read_timeout = 10 # 读取超时时长
10 | write_timeout = 10 # 写入超时时长
11 | max_header_bytes = 20 # 最大的header大小,二进制位长度
12 |
13 | [https]
14 | addr =":4433" # 监听地址, default ":8700"
15 | read_timeout = 10 # 读取超时时长
16 | write_timeout = 10 # 写入超时时长
17 | max_header_bytes = 20 # 最大的header大小,二进制位长度
--------------------------------------------------------------------------------
/conf/dev/redis_map.toml:
--------------------------------------------------------------------------------
1 | [list]
2 | [list.default]
3 | proxy_list = ["127.0.0.1:6379"]
4 | conn_timeout = 500
5 | password = ""
6 | db = 0
7 | read_timeout = 1000
8 | write_timeout = 1000
9 | max_active = 200
10 | max_idle = 500
--------------------------------------------------------------------------------
/control.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #############################################
3 | ## main
4 | ## 以托管方式, 启动服务
5 | ## control.sh脚本, 必须实现start方法
6 | #############################################
7 |
8 | set -e
9 | workspace=$(cd $(dirname $0) && pwd -P)
10 | cd $workspace
11 | app=gatekeeper
12 | cmd_run=" run -c conf/dev/ -p"
13 |
14 | function check_go_version() {
15 | use_go_version="1120"
16 | go_version=`go version |grep -Eo '([0-9])\.([0-9]{1,2})\.([0-9]*)' |awk -F '.' '{print $1 $2 $3}'`
17 | if [ ! -n "$go_version" ] || [ "$go_version" -le "$use_go_version" ];then
18 | echo "go version < 1.12.0 pleace upgreate"
19 | echo "Installation package download address : https://golang.org/dl/ or https://golang.google.cn/dl/"
20 | echo "Installation tutorial address : https://www.runoob.com/go/go-environment.html"
21 | exit -1
22 | fi
23 | }
24 |
25 | function run() {
26 | panel_type=$1
27 | cmd_run="${cmd_run} ${panel_type}"
28 |
29 | # bin run gatekeeper
30 | if [ -f "${app}" ];then
31 | echo "run bin gatekeeper"
32 | chmod 755 ${app}
33 | eval ./${app}${cmd_run}
34 | return
35 | fi
36 |
37 | # go run gatekeeper
38 | if [ -f "main.go" ];then
39 | check_go_version
40 | echo "go run main.go ${cmd_run}"
41 | eval go run main.go ${cmd_run}
42 | return
43 | fi
44 | echo "not found run file"
45 | }
46 |
47 | function help() {
48 | echo -e "Control command manager"
49 | echo -e "Usage:"
50 | echo -e "\t[command]"
51 | echo -e "\n"
52 | echo -e "Available Commands:"
53 | echo -e "\tstart_proxy \t start gatekeeper proxy"
54 | echo -e "\tstart_control \t start gatekeeper control"
55 | echo -e "\tstart_both \t start gatekeeper control && proxy"
56 | echo -e "\n"
57 | echo -e "Flags:"
58 | echo -e "\t-h,\t--help\thelp for this command"
59 | }
60 |
61 | action=$1
62 | case $action in
63 | -h|--help)
64 | help
65 | ;;
66 | "start_proxy" )
67 | run proxy
68 | ;;
69 | "start_control" )
70 | run control
71 | ;;
72 | "start_both" )
73 | run both
74 | ;;
75 | * )
76 | help
77 | ;;
78 | esac
79 |
--------------------------------------------------------------------------------
/dashboard_middleware/recovery.go:
--------------------------------------------------------------------------------
1 | package dashboard_middleware
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "github.com/didi/gatekeeper/golang_common/lib"
7 | "github.com/didi/gatekeeper/golang_common/trace"
8 | "github.com/didi/gatekeeper/public"
9 | "github.com/gin-gonic/gin"
10 | "runtime/debug"
11 | )
12 |
13 | func RecoveryMiddleware() gin.HandlerFunc {
14 | return func(c *gin.Context) {
15 | defer func() {
16 | if err := recover(); err != nil {
17 | if lib.ConfBase.Log.On {
18 | public.GinLogWarning(c, trace.DLTagUndefined, map[string]interface{}{
19 | "error": fmt.Sprint(err),
20 | "stack": string(debug.Stack()),
21 | })
22 | }
23 | if lib.ConfBase.Base.DebugMode != "debug" {
24 | ResponseError(c, 500, errors.New("内部错误"))
25 | return
26 | } else {
27 | ResponseError(c, 500, errors.New(fmt.Sprint(err)))
28 | return
29 | }
30 | }
31 | }()
32 | c.Next()
33 | }
34 | }
--------------------------------------------------------------------------------
/dashboard_middleware/response.go:
--------------------------------------------------------------------------------
1 | package dashboard_middleware
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "github.com/didi/gatekeeper/golang_common/lib"
7 | "github.com/didi/gatekeeper/public"
8 | "github.com/gin-gonic/gin"
9 | "strings"
10 | )
11 |
12 | type ResponseCode int
13 |
14 | //1000以下为通用码,1000以上为用户自定义码
15 | const (
16 | SuccessCode ResponseCode = iota
17 | UndefErrorCode
18 | ValidErrorCode
19 | InternalErrorCode
20 | InvalidRequestErrorCode ResponseCode = 401
21 | CustomizeCode ResponseCode = 1000
22 | )
23 |
24 | type Response struct {
25 | ErrorCode ResponseCode `json:"errno"`
26 | ErrorMsg string `json:"errmsg"`
27 | Data interface{} `json:"data"`
28 | TraceId interface{} `json:"trace_id"`
29 | Stack interface{} `json:"stack"`
30 | }
31 |
32 | func ResponseError(c *gin.Context, code ResponseCode, err error) {
33 | traceContext := public.GetGinTraceContext(c)
34 | stack := ""
35 | if c.Query("is_debug") == "1" || lib.GetConfEnv() == "dev" {
36 | stack = strings.Replace(fmt.Sprintf("%+v", err), err.Error()+"\n", "", -1)
37 | }
38 |
39 | resp := &Response{ErrorCode: code, ErrorMsg: err.Error(), Data: "", TraceId: traceContext.TraceId, Stack: stack}
40 | c.JSON(200, resp)
41 | response, _ := json.Marshal(resp)
42 | c.Set("response", string(response))
43 | c.AbortWithError(200, err)
44 | }
45 |
46 | func ResponseSuccess(c *gin.Context, data interface{}) {
47 | traceContext := public.GetGinTraceContext(c)
48 | resp := &Response{ErrorCode: SuccessCode, ErrorMsg: "", Data: data, TraceId: traceContext.TraceId}
49 | c.JSON(200, resp)
50 | response, _ := json.Marshal(resp)
51 | c.Set("response", string(response))
52 | }
53 |
--------------------------------------------------------------------------------
/dashboard_middleware/session_auth.go:
--------------------------------------------------------------------------------
1 | package dashboard_middleware
2 |
3 | import (
4 | "errors"
5 | "github.com/didi/gatekeeper/public"
6 | "github.com/gin-gonic/contrib/sessions"
7 | "github.com/gin-gonic/gin"
8 | )
9 |
10 | func SessionAuthMiddleware() gin.HandlerFunc {
11 | return func(c *gin.Context) {
12 | session := sessions.Default(c)
13 | if adminInfo, ok := session.Get(public.AdminSessionInfoKey).(string); !ok || adminInfo == "" {
14 | ResponseError(c, InternalErrorCode, errors.New("user not login"))
15 | c.Abort()
16 | return
17 | }
18 | c.Next()
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/dashboard_router/httpserver.go:
--------------------------------------------------------------------------------
1 | package dashboard_router
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "github.com/didi/gatekeeper/golang_common/lib"
7 | "github.com/didi/gatekeeper/golang_common/zerolog/log"
8 | "github.com/gin-gonic/gin"
9 | "net/http"
10 | "time"
11 | )
12 |
13 | var (
14 | HttpSrvHandler *http.Server
15 | )
16 |
17 | func HttpServerRun() {
18 | gin.SetMode(lib.GetStringConf("base.base.debug_mode"))
19 | r := InitRouter()
20 | HttpSrvHandler = &http.Server{
21 | Addr: lib.GetStringConf("base.http.addr"),
22 | Handler: r,
23 | ReadTimeout: time.Duration(lib.GetIntConf("base.http.read_timeout")) * time.Second,
24 | WriteTimeout: time.Duration(lib.GetIntConf("base.http.write_timeout")) * time.Second,
25 | MaxHeaderBytes: 1 << uint(lib.GetIntConf("base.http.max_header_bytes")),
26 | }
27 | go func() {
28 | log.Info().Msg(lib.Purple(fmt.Sprintf("start HTTP control service [http://127.0.0.1%s/dist/]", lib.GetStringConf("base.http.addr"))))
29 | if err := HttpSrvHandler.ListenAndServe(); err != nil {
30 | log.Error().Msg(lib.Purple(fmt.Sprintf("failed to start HTTP service service [%s] %v", lib.GetStringConf("base.http.addr"), err)))
31 | }
32 | }()
33 | }
34 |
35 | func HttpServerStop() {
36 | ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
37 | defer cancel()
38 | if err := HttpSrvHandler.Shutdown(ctx); err != nil {
39 | log.Error().Msg(lib.Purple(fmt.Sprintf("HttpServerStop err:%v", err)))
40 | }
41 | log.Error().Msg(lib.Purple(fmt.Sprintf("stop HTTP control service [%s]", lib.GetStringConf("base.http.addr"))))
42 | }
43 |
--------------------------------------------------------------------------------
/debug.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -x
3 | export GO111MODULE=on
4 | export GOPROXY=https://goproxy.cn
5 | go build -o bin/gatekeeper
6 | rm -rf ./logs/*
7 | ps aux | grep gatekeeper | grep -v 'grep' | awk '{print $2}' | xargs kill
8 |
9 | action=$1
10 | case $action in
11 | "control" )
12 | ./bin/gatekeeper -c ./conf/dev/ -p $action
13 | ;;
14 | "proxy" )
15 | ./bin/gatekeeper -c ./conf/dev/ -p $action
16 | ;;
17 | * )
18 | echo "unknown command"
19 | exit 1
20 | ;;
21 | esac
--------------------------------------------------------------------------------
/dist/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/didi/GateKeeper/3c5211ab37040f47c5c9bd236adb06e8c69127d3/dist/favicon.ico
--------------------------------------------------------------------------------
/dist/static/css/chunk-1c7e619f.0be79fdd.css:
--------------------------------------------------------------------------------
1 | .waves-ripple{position:absolute;border-radius:100%;background-color:rgba(0,0,0,.15);background-clip:padding-box;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transform:scale(0);transform:scale(0);opacity:1}.waves-ripple.z-active{opacity:0;-webkit-transform:scale(2);transform:scale(2);-webkit-transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out,-webkit-transform .6s ease-out}.pagination_container[data-v-07260ece]{background:#fff;padding:32px 16px}.pagination_container.hidden[data-v-07260ece]{display:none}.app-container .filter-container[data-v-4c48a17c]{display:-webkit-box;display:-ms-flexbox;display:flex;padding:20px;-webkit-box-shadow:0 2px 6px 0 rgba(26,27,31,.12);box-shadow:0 2px 6px 0 rgba(26,27,31,.12);border-radius:5px;background-color:#fff;margin-bottom:6px}.app-container .filter-container-input[data-v-4c48a17c]{width:20rem;border-radius:4px}.app-container .filter-container-btn[data-v-4c48a17c]{width:141px;background:#3d6aff;border-radius:4px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.app-container-table[data-v-4c48a17c]{padding:20px;-webkit-box-shadow:0 2px 6px 0 rgba(26,27,31,.12);box-shadow:0 2px 6px 0 rgba(26,27,31,.12);border-radius:5px;background-color:#fff}.app-container-table .btn[data-v-4c48a17c]{font-family:PingFangSC-Regular;font-size:14px;color:#3d6aff;text-align:left;line-height:22px;font-weight:400}[data-v-4c48a17c] .filter-container-input .el-input-group__append{background-color:#fff;width:40px}
--------------------------------------------------------------------------------
/dist/static/css/chunk-294e231b.d3b4ac8e.css:
--------------------------------------------------------------------------------
1 | .mixin-components-container[data-v-8bcdbc8a]{background-color:#f0f2f5;padding:30px;min-height:calc(100vh - 84px)}.component-item[data-v-8bcdbc8a]{min-height:100px}.el-select .el-input[data-v-8bcdbc8a]{width:130px}.input-with-select .el-input-group__prepend[data-v-8bcdbc8a]{background-color:#fff}
--------------------------------------------------------------------------------
/dist/static/css/chunk-3f238847.a2fda0b3.css:
--------------------------------------------------------------------------------
1 | .errPage-container[data-v-61343d02]{width:800px;max-width:100%;margin:100px auto}.errPage-container .pan-back-btn[data-v-61343d02]{background:#008489;color:#fff;border:none!important}.errPage-container .pan-gif[data-v-61343d02]{margin:0 auto;display:block}.errPage-container .pan-img[data-v-61343d02]{display:block;margin:0 auto;width:100%}.errPage-container .text-jumbo[data-v-61343d02]{font-size:60px;font-weight:700;color:#484848}.errPage-container .list-unstyled[data-v-61343d02]{font-size:14px}.errPage-container .list-unstyled li[data-v-61343d02]{padding-bottom:5px}.errPage-container .list-unstyled a[data-v-61343d02]{color:#008489;text-decoration:none}.errPage-container .list-unstyled a[data-v-61343d02]:hover{text-decoration:underline}
--------------------------------------------------------------------------------
/dist/static/css/chunk-3f3d4b77.fe722f73.css:
--------------------------------------------------------------------------------
1 | .waves-ripple{position:absolute;border-radius:100%;background-color:rgba(0,0,0,.15);background-clip:padding-box;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transform:scale(0);transform:scale(0);opacity:1}.waves-ripple.z-active{opacity:0;-webkit-transform:scale(2);transform:scale(2);-webkit-transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out,-webkit-transform .6s ease-out}.pagination_container[data-v-07260ece]{background:#fff;padding:32px 16px}.pagination_container.hidden[data-v-07260ece]{display:none}.app-container .filter-container[data-v-ef1b8ba4]{display:-webkit-box;display:-ms-flexbox;display:flex;padding:20px;-webkit-box-shadow:0 2px 6px 0 rgba(26,27,31,.12);box-shadow:0 2px 6px 0 rgba(26,27,31,.12);border-radius:5px;background-color:#fff;margin-bottom:6px}.app-container .filter-container-input[data-v-ef1b8ba4]{width:20rem;border-radius:4px}.app-container .filter-container-btn[data-v-ef1b8ba4]{width:141px;background:#3d6aff;border-radius:4px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.app-container-table[data-v-ef1b8ba4]{padding:20px;-webkit-box-shadow:0 2px 6px 0 rgba(26,27,31,.12);box-shadow:0 2px 6px 0 rgba(26,27,31,.12);border-radius:5px;background-color:#fff}.app-container-table .btn[data-v-ef1b8ba4]{font-family:PingFangSC-Regular;font-size:14px;color:#3d6aff;text-align:left;line-height:22px;font-weight:400}[data-v-ef1b8ba4] .filter-container-input .el-input-group__append{background-color:#fff;width:40px}
--------------------------------------------------------------------------------
/dist/static/css/chunk-4ce61457.41f5667e.css:
--------------------------------------------------------------------------------
1 | .mixin-components-container[data-v-6a0bc019]{background-color:#f0f2f5;padding:30px;min-height:calc(100vh - 84px)}.component-item[data-v-6a0bc019]{min-height:100px}.card[data-v-6a0bc019]{margin-top:20px}.bottom[data-v-6a0bc019]{background:#fff;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-pack:distribute;justify-content:space-around;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-shadow:0 2px 12px 0 rgb(0 0 0/10%);box-shadow:0 2px 12px 0 rgb(0 0 0/10%);margin-top:10px;padding:30px 0}
--------------------------------------------------------------------------------
/dist/static/css/chunk-61ae4e7a.93d95231.css:
--------------------------------------------------------------------------------
1 | @supports (-webkit-mask:none) and (not (cater-color:#fff)){.login-container .el-input input{color:#fff}}.login-container .el-input{display:inline-block;height:47px;width:85%}.login-container .el-input input{background:transparent;border:0;-webkit-appearance:none;border-radius:0;padding:12px 5px 12px 15px;color:#fff;height:47px;caret-color:#fff}.login-container .el-input input:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px #283443 inset!important;box-shadow:inset 0 0 0 1000px #283443!important;-webkit-text-fill-color:#fff!important}.login-container .el-form-item{border:1px solid hsla(0,0%,100%,.1);background:rgba(0,0,0,.1);border-radius:5px;color:#454545}.login-container[data-v-11647fdd]{min-height:100%;width:100%;background-color:#2d3a4b;overflow:hidden}.login-container .login-form[data-v-11647fdd]{position:relative;width:520px;max-width:100%;padding:160px 35px 0;margin:0 auto;overflow:hidden}.login-container .tips[data-v-11647fdd]{font-size:14px;color:#fff;margin-bottom:10px}.login-container .tips span[data-v-11647fdd]:first-of-type{margin-right:16px}.login-container .svg-container[data-v-11647fdd]{padding:6px 5px 6px 15px;color:#889aa4;vertical-align:middle;width:30px;display:inline-block}.login-container .title-container[data-v-11647fdd]{position:relative}.login-container .title-container .title[data-v-11647fdd]{font-size:26px;color:#eee;margin:0 auto 40px auto;text-align:center;font-weight:700}.login-container .show-pwd[data-v-11647fdd]{position:absolute;right:10px;top:7px;font-size:16px;color:#889aa4;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.login-container .thirdparty-button[data-v-11647fdd]{position:absolute;right:0;bottom:6px}@media only screen and (max-width:470px){.login-container .thirdparty-button[data-v-11647fdd]{display:none}}
--------------------------------------------------------------------------------
/dist/static/css/chunk-6525d41e.b1d9f1ec.css:
--------------------------------------------------------------------------------
1 | .mixin-components-container[data-v-19bb35ad]{background-color:#f0f2f5;padding:30px;min-height:calc(100vh - 84px)}.component-item[data-v-19bb35ad]{min-height:100px}.el-select .el-input[data-v-19bb35ad]{width:130px}.input-with-select .el-input-group__prepend[data-v-19bb35ad]{background-color:#fff}
--------------------------------------------------------------------------------
/dist/static/css/chunk-68b61de5.fb787c4e.css:
--------------------------------------------------------------------------------
1 | .mixin-components-container[data-v-e17f2ec0]{background-color:#f0f2f5;padding:30px;min-height:calc(100vh - 84px)}.component-item[data-v-e17f2ec0]{min-height:100px}.card[data-v-e17f2ec0]{margin-top:20px}.bottom[data-v-e17f2ec0]{background:#fff;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-pack:distribute;justify-content:space-around;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-shadow:0 2px 12px 0 rgb(0 0 0/10%);box-shadow:0 2px 12px 0 rgb(0 0 0/10%);margin-top:10px;padding:30px 0}
--------------------------------------------------------------------------------
/dist/static/css/chunk-6f6c0d4e.c5f2d082.css:
--------------------------------------------------------------------------------
1 | .chart-container[data-v-33d2dd29]{position:relative;width:100%;height:calc(100vh - 84px)}
--------------------------------------------------------------------------------
/dist/static/css/chunk-80699a70.c0f8cc73.css:
--------------------------------------------------------------------------------
1 | .panel-group[data-v-ec27f13c]{margin-top:18px}.panel-group .card-panel-col[data-v-ec27f13c]{margin-bottom:32px}.panel-group .card-panel[data-v-ec27f13c]{height:108px;font-size:12px;position:relative;overflow:hidden;color:#666;background:#fff;-webkit-box-shadow:4px 4px 40px rgba(0,0,0,.05);box-shadow:4px 4px 40px rgba(0,0,0,.05);border-color:rgba(0,0,0,.05)}.panel-group .card-panel .icon-people[data-v-ec27f13c]{color:#40c9c6}.panel-group .card-panel .icon-message[data-v-ec27f13c]{color:#36a3f7}.panel-group .card-panel .icon-money[data-v-ec27f13c]{color:#f4516c}.panel-group .card-panel .icon-shopping[data-v-ec27f13c]{color:#34bfa3}.panel-group .card-panel .card-panel-icon-wrapper[data-v-ec27f13c]{float:left;margin:14px 0 0 14px;padding:16px;-webkit-transition:all .38s ease-out;transition:all .38s ease-out;border-radius:6px}.panel-group .card-panel .card-panel-icon[data-v-ec27f13c]{float:left;font-size:48px}.panel-group .card-panel .card-panel-description[data-v-ec27f13c]{float:right;font-weight:700;margin:26px;margin-left:0}.panel-group .card-panel .card-panel-description .card-panel-text[data-v-ec27f13c]{line-height:18px;color:rgba(0,0,0,.45);font-size:16px;margin-bottom:12px}.panel-group .card-panel .card-panel-description .card-panel-num[data-v-ec27f13c]{font-size:20px}@media (max-width:550px){.card-panel-description[data-v-ec27f13c]{display:none}.card-panel-icon-wrapper[data-v-ec27f13c]{float:none!important;width:100%;height:100%;margin:0!important}.card-panel-icon-wrapper .svg-icon[data-v-ec27f13c]{display:block;margin:14px auto!important;float:none!important}}.dashboard-editor-container[data-v-4ac7101a]{padding:32px;position:relative}.dashboard-editor-container .github-corner[data-v-4ac7101a]{position:absolute;top:0;border:0;right:0}.dashboard-editor-container .chart-wrapper[data-v-4ac7101a]{background:#fff;padding:16px 16px 0;margin-bottom:32px}@media (max-width:1024px){.chart-wrapper[data-v-4ac7101a]{padding:8px}}
--------------------------------------------------------------------------------
/dist/static/css/chunk-bcebd8aa.78a33c26.css:
--------------------------------------------------------------------------------
1 | .chart-container[data-v-da4d48fa]{position:relative;width:100%;height:calc(100vh - 84px)}
--------------------------------------------------------------------------------
/dist/static/css/chunk-db410d48.50024827.css:
--------------------------------------------------------------------------------
1 | .wrapper-class[data-v-a6a3aeee]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;margin-top:15px}.wrapper-class .el-icon-question[data-v-a6a3aeee]{color:#36a3f7}
--------------------------------------------------------------------------------
/dist/static/css/chunk-e9dba01a.b0fc6a10.css:
--------------------------------------------------------------------------------
1 | .mixin-components-container[data-v-550e716b]{background-color:#f0f2f5;padding:30px;min-height:calc(100vh - 84px)}.component-item[data-v-550e716b]{min-height:100px}.el-select .el-input[data-v-550e716b]{width:130px}.input-with-select .el-input-group__prepend[data-v-550e716b]{background-color:#fff}
--------------------------------------------------------------------------------
/dist/static/fonts/element-icons.535877f5.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/didi/GateKeeper/3c5211ab37040f47c5c9bd236adb06e8c69127d3/dist/static/fonts/element-icons.535877f5.woff
--------------------------------------------------------------------------------
/dist/static/fonts/element-icons.732389de.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/didi/GateKeeper/3c5211ab37040f47c5c9bd236adb06e8c69127d3/dist/static/fonts/element-icons.732389de.ttf
--------------------------------------------------------------------------------
/dist/static/img/401.089007e7.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/didi/GateKeeper/3c5211ab37040f47c5c9bd236adb06e8c69127d3/dist/static/img/401.089007e7.gif
--------------------------------------------------------------------------------
/dist/static/img/404.a57b6f31.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/didi/GateKeeper/3c5211ab37040f47c5c9bd236adb06e8c69127d3/dist/static/img/404.a57b6f31.png
--------------------------------------------------------------------------------
/dist/static/img/404_cloud.0f4bc32b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/didi/GateKeeper/3c5211ab37040f47c5c9bd236adb06e8c69127d3/dist/static/img/404_cloud.0f4bc32b.png
--------------------------------------------------------------------------------
/dist/static/img/double-arrow-left.56942267.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/dist/static/img/logo.e3a14490.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/dist/static/js/chunk-2d230fe7.f069ed37.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d230fe7"],{ef3c:function(e,r,n){"use strict";n.r(r);n("8dee");var t,u,a={created:function(){var e=this.$route,r=e.params,n=e.query,t=r.path;this.$router.replace({path:"/"+t,query:n})},render:function(e){return e()}},c=a,o=n("cba8"),p=Object(o["a"])(c,t,u,!1,null,null,null);r["default"]=p.exports}}]);
--------------------------------------------------------------------------------
/dist/static/js/chunk-2f5ea260.34edaec3.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2f5ea260"],{"1db4":function(t,s,a){"use strict";a.r(s);var c=function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("div",{staticClass:"wscn-http404-container"},[a("div",{staticClass:"wscn-http404"},[t._m(0),a("div",{staticClass:"bullshit"},[a("div",{staticClass:"bullshit__oops"},[t._v("OOPS!")]),t._m(1),a("div",{staticClass:"bullshit__headline"},[t._v(t._s(t.message))]),a("div",{staticClass:"bullshit__info"},[t._v(" Please check that the URL you entered is correct, or click the button below to return to the homepage. ")]),a("a",{staticClass:"bullshit__return-home",attrs:{href:""}},[t._v("Back to home")])])])])},e=[function(){var t=this,s=t.$createElement,c=t._self._c||s;return c("div",{staticClass:"pic-404"},[c("img",{staticClass:"pic-404__parent",attrs:{src:a("a36b"),alt:"404"}}),c("img",{staticClass:"pic-404__child left",attrs:{src:a("26fc"),alt:"404"}}),c("img",{staticClass:"pic-404__child mid",attrs:{src:a("26fc"),alt:"404"}}),c("img",{staticClass:"pic-404__child right",attrs:{src:a("26fc"),alt:"404"}})])},function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("div",{staticClass:"bullshit__info"},[t._v(" All rights reserved "),a("a",{staticStyle:{color:"#20a0ff"},attrs:{href:"https://wallstreetcn.com",target:"_blank"}},[t._v(" wallstreetcn ")])])}],i={name:"Page404",computed:{message:function(){return"The webmaster said that you can not enter this page..."}}},l=i,n=(a("26c2"),a("cba8")),r=Object(n["a"])(l,c,e,!1,null,"c4f16cd2",null);s["default"]=r.exports},"26c2":function(t,s,a){"use strict";a("ff95")},"26fc":function(t,s,a){t.exports=a.p+"static/img/404_cloud.0f4bc32b.png"},a36b:function(t,s,a){t.exports=a.p+"static/img/404.a57b6f31.png"},ff95:function(t,s,a){}}]);
--------------------------------------------------------------------------------
/dist/static/js/chunk-3f238847.dde743ce.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-3f238847"],{"24e2":function(t,a,i){"use strict";i.r(a);var e=function(){var t=this,a=t.$createElement,i=t._self._c||a;return i("div",{staticClass:"errPage-container"},[i("el-button",{staticClass:"pan-back-btn",attrs:{icon:"el-icon-arrow-left"},on:{click:t.back}},[t._v(" 返回 ")]),i("el-row",[i("el-col",{attrs:{span:12}},[i("h1",{staticClass:"text-jumbo text-ginormous"},[t._v(" Oops! ")]),t._v(" gif来源 "),i("a",{attrs:{href:"https://zh.airbnb.com/",target:"_blank"}},[t._v("airbnb")]),t._v(" 页面 "),i("h2",[t._v("你没有权限去该页面")]),i("h6",[t._v("如有不满请联系你领导")]),i("ul",{staticClass:"list-unstyled"},[i("li",[t._v("或者你可以去:")]),i("li",{staticClass:"link-type"},[i("router-link",{attrs:{to:"/dashboard"}},[t._v(" 回首页 ")])],1),i("li",{staticClass:"link-type"},[i("a",{attrs:{href:"https://www.taobao.com/"}},[t._v("随便看看")])]),i("li",[i("a",{attrs:{href:"#"},on:{click:function(a){a.preventDefault(),t.dialogVisible=!0}}},[t._v("点我看图")])])])]),i("el-col",{attrs:{span:12}},[i("img",{attrs:{src:t.errGif,width:"313",height:"428",alt:"Girl has dropped her ice cream."}})])],1),i("el-dialog",{attrs:{visible:t.dialogVisible,title:"随便看"},on:{"update:visible":function(a){t.dialogVisible=a}}},[i("img",{staticClass:"pan-img",attrs:{src:t.ewizardClap}})])],1)},s=[],r=i("cc6c"),c=i.n(r),l={name:"Page401",data:function(){return{errGif:c.a+"?"+ +new Date,ewizardClap:"https://wpimg.wallstcn.com/007ef517-bafd-4066-aae4-6883632d9646",dialogVisible:!1}},methods:{back:function(){this.$route.query.noGoBack?this.$router.push({path:"/dashboard"}):this.$router.go(-1)}}},n=l,o=(i("663b"),i("cba8")),u=Object(o["a"])(n,e,s,!1,null,"61343d02",null);a["default"]=u.exports},"663b":function(t,a,i){"use strict";i("ec97")},cc6c:function(t,a,i){t.exports=i.p+"static/img/401.089007e7.gif"},ec97:function(t,a,i){}}]);
--------------------------------------------------------------------------------
/dist/static/js/chunk-57e15452.3a533841.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-57e15452"],{"69b0":function(n,t){n.exports=Object.is||function(n,t){return n===t?0!==n||1/n===1/t:n!=n&&t!=t}},b829:function(n,t,e){"use strict";e.r(t);e("d91d");var r,i,o={name:"AuthRedirect",created:function(){var n=window.location.search.slice(1);window.localStorage&&(window.localStorage.setItem("x-admin-oauth-code",n),window.close())},render:function(n){return n()}},a=o,c=e("cba8"),u=Object(c["a"])(a,r,i,!1,null,null,null);t["default"]=u.exports},d91d:function(n,t,e){"use strict";var r=e("a86f"),i=e("69b0"),o=e("f417");e("c46f")("search",1,(function(n,t,e,a){return[function(e){var r=n(this),i=void 0==e?void 0:e[t];return void 0!==i?i.call(e,r):new RegExp(e)[t](String(r))},function(n){var t=a(e,n,this);if(t.done)return t.value;var c=r(n),u=String(this),d=c.lastIndex;i(d,0)||(c.lastIndex=0);var l=o(c,u);return i(c.lastIndex,d)||(c.lastIndex=d),null===l?-1:l.index}]}))}}]);
--------------------------------------------------------------------------------
/dist_backup/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/didi/GateKeeper/3c5211ab37040f47c5c9bd236adb06e8c69127d3/dist_backup/favicon.ico
--------------------------------------------------------------------------------
/dist_backup/static/css/chunk-294e231b.d3b4ac8e.css:
--------------------------------------------------------------------------------
1 | .mixin-components-container[data-v-8bcdbc8a]{background-color:#f0f2f5;padding:30px;min-height:calc(100vh - 84px)}.component-item[data-v-8bcdbc8a]{min-height:100px}.el-select .el-input[data-v-8bcdbc8a]{width:130px}.input-with-select .el-input-group__prepend[data-v-8bcdbc8a]{background-color:#fff}
--------------------------------------------------------------------------------
/dist_backup/static/css/chunk-335e7249.6d24dacd.css:
--------------------------------------------------------------------------------
1 | .waves-ripple{position:absolute;border-radius:100%;background-color:rgba(0,0,0,.15);background-clip:padding-box;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transform:scale(0);transform:scale(0);opacity:1}.waves-ripple.z-active{opacity:0;-webkit-transform:scale(2);transform:scale(2);-webkit-transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out,-webkit-transform .6s ease-out}.pagination-container[data-v-6af373ef]{background:#fff;padding:32px 16px}.pagination-container.hidden[data-v-6af373ef]{display:none}
--------------------------------------------------------------------------------
/dist_backup/static/css/chunk-3f238847.a2fda0b3.css:
--------------------------------------------------------------------------------
1 | .errPage-container[data-v-61343d02]{width:800px;max-width:100%;margin:100px auto}.errPage-container .pan-back-btn[data-v-61343d02]{background:#008489;color:#fff;border:none!important}.errPage-container .pan-gif[data-v-61343d02]{margin:0 auto;display:block}.errPage-container .pan-img[data-v-61343d02]{display:block;margin:0 auto;width:100%}.errPage-container .text-jumbo[data-v-61343d02]{font-size:60px;font-weight:700;color:#484848}.errPage-container .list-unstyled[data-v-61343d02]{font-size:14px}.errPage-container .list-unstyled li[data-v-61343d02]{padding-bottom:5px}.errPage-container .list-unstyled a[data-v-61343d02]{color:#008489;text-decoration:none}.errPage-container .list-unstyled a[data-v-61343d02]:hover{text-decoration:underline}
--------------------------------------------------------------------------------
/dist_backup/static/css/chunk-5c8c1f18.25617263.css:
--------------------------------------------------------------------------------
1 | .mixin-components-container[data-v-686a0906]{background-color:#f0f2f5;padding:30px;min-height:calc(100vh - 84px)}.component-item[data-v-686a0906]{min-height:100px}.card[data-v-686a0906]{margin-top:20px}.bottom[data-v-686a0906]{background:#fff;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-pack:distribute;justify-content:space-around;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-shadow:0 2px 12px 0 rgb(0 0 0/10%);box-shadow:0 2px 12px 0 rgb(0 0 0/10%);margin-top:10px;padding:30px 0}
--------------------------------------------------------------------------------
/dist_backup/static/css/chunk-61ae4e7a.93d95231.css:
--------------------------------------------------------------------------------
1 | @supports (-webkit-mask:none) and (not (cater-color:#fff)){.login-container .el-input input{color:#fff}}.login-container .el-input{display:inline-block;height:47px;width:85%}.login-container .el-input input{background:transparent;border:0;-webkit-appearance:none;border-radius:0;padding:12px 5px 12px 15px;color:#fff;height:47px;caret-color:#fff}.login-container .el-input input:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px #283443 inset!important;box-shadow:inset 0 0 0 1000px #283443!important;-webkit-text-fill-color:#fff!important}.login-container .el-form-item{border:1px solid hsla(0,0%,100%,.1);background:rgba(0,0,0,.1);border-radius:5px;color:#454545}.login-container[data-v-11647fdd]{min-height:100%;width:100%;background-color:#2d3a4b;overflow:hidden}.login-container .login-form[data-v-11647fdd]{position:relative;width:520px;max-width:100%;padding:160px 35px 0;margin:0 auto;overflow:hidden}.login-container .tips[data-v-11647fdd]{font-size:14px;color:#fff;margin-bottom:10px}.login-container .tips span[data-v-11647fdd]:first-of-type{margin-right:16px}.login-container .svg-container[data-v-11647fdd]{padding:6px 5px 6px 15px;color:#889aa4;vertical-align:middle;width:30px;display:inline-block}.login-container .title-container[data-v-11647fdd]{position:relative}.login-container .title-container .title[data-v-11647fdd]{font-size:26px;color:#eee;margin:0 auto 40px auto;text-align:center;font-weight:700}.login-container .show-pwd[data-v-11647fdd]{position:absolute;right:10px;top:7px;font-size:16px;color:#889aa4;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.login-container .thirdparty-button[data-v-11647fdd]{position:absolute;right:0;bottom:6px}@media only screen and (max-width:470px){.login-container .thirdparty-button[data-v-11647fdd]{display:none}}
--------------------------------------------------------------------------------
/dist_backup/static/css/chunk-6525d41e.b1d9f1ec.css:
--------------------------------------------------------------------------------
1 | .mixin-components-container[data-v-19bb35ad]{background-color:#f0f2f5;padding:30px;min-height:calc(100vh - 84px)}.component-item[data-v-19bb35ad]{min-height:100px}.el-select .el-input[data-v-19bb35ad]{width:130px}.input-with-select .el-input-group__prepend[data-v-19bb35ad]{background-color:#fff}
--------------------------------------------------------------------------------
/dist_backup/static/css/chunk-68b61de5.fb787c4e.css:
--------------------------------------------------------------------------------
1 | .mixin-components-container[data-v-e17f2ec0]{background-color:#f0f2f5;padding:30px;min-height:calc(100vh - 84px)}.component-item[data-v-e17f2ec0]{min-height:100px}.card[data-v-e17f2ec0]{margin-top:20px}.bottom[data-v-e17f2ec0]{background:#fff;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-pack:distribute;justify-content:space-around;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-shadow:0 2px 12px 0 rgb(0 0 0/10%);box-shadow:0 2px 12px 0 rgb(0 0 0/10%);margin-top:10px;padding:30px 0}
--------------------------------------------------------------------------------
/dist_backup/static/css/chunk-6f6c0d4e.c5f2d082.css:
--------------------------------------------------------------------------------
1 | .chart-container[data-v-33d2dd29]{position:relative;width:100%;height:calc(100vh - 84px)}
--------------------------------------------------------------------------------
/dist_backup/static/css/chunk-7be427f9.9fb4309b.css:
--------------------------------------------------------------------------------
1 | .waves-ripple{position:absolute;border-radius:100%;background-color:rgba(0,0,0,.15);background-clip:padding-box;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transform:scale(0);transform:scale(0);opacity:1}.waves-ripple.z-active{opacity:0;-webkit-transform:scale(2);transform:scale(2);-webkit-transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out,-webkit-transform .6s ease-out}.pagination-container[data-v-6af373ef]{background:#fff;padding:32px 16px}.pagination-container.hidden[data-v-6af373ef]{display:none}.app-container .filter-container[data-v-4c48a17c]{display:-webkit-box;display:-ms-flexbox;display:flex;padding:20px;-webkit-box-shadow:0 2px 6px 0 rgba(26,27,31,.12);box-shadow:0 2px 6px 0 rgba(26,27,31,.12);border-radius:5px;background-color:#fff;margin-bottom:6px}.app-container .filter-container-input[data-v-4c48a17c]{width:20rem;border-radius:4px}.app-container .filter-container-btn[data-v-4c48a17c]{width:141px;background:#3d6aff;border-radius:4px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.app-container-table[data-v-4c48a17c]{padding:20px;-webkit-box-shadow:0 2px 6px 0 rgba(26,27,31,.12);box-shadow:0 2px 6px 0 rgba(26,27,31,.12);border-radius:5px;background-color:#fff}.app-container-table .btn[data-v-4c48a17c]{font-family:PingFangSC-Regular;font-size:14px;color:#3d6aff;text-align:left;line-height:22px;font-weight:400}[data-v-4c48a17c] .filter-container-input .el-input-group__append{background-color:#fff;width:40px}
--------------------------------------------------------------------------------
/dist_backup/static/css/chunk-80699a70.c0f8cc73.css:
--------------------------------------------------------------------------------
1 | .panel-group[data-v-ec27f13c]{margin-top:18px}.panel-group .card-panel-col[data-v-ec27f13c]{margin-bottom:32px}.panel-group .card-panel[data-v-ec27f13c]{height:108px;font-size:12px;position:relative;overflow:hidden;color:#666;background:#fff;-webkit-box-shadow:4px 4px 40px rgba(0,0,0,.05);box-shadow:4px 4px 40px rgba(0,0,0,.05);border-color:rgba(0,0,0,.05)}.panel-group .card-panel .icon-people[data-v-ec27f13c]{color:#40c9c6}.panel-group .card-panel .icon-message[data-v-ec27f13c]{color:#36a3f7}.panel-group .card-panel .icon-money[data-v-ec27f13c]{color:#f4516c}.panel-group .card-panel .icon-shopping[data-v-ec27f13c]{color:#34bfa3}.panel-group .card-panel .card-panel-icon-wrapper[data-v-ec27f13c]{float:left;margin:14px 0 0 14px;padding:16px;-webkit-transition:all .38s ease-out;transition:all .38s ease-out;border-radius:6px}.panel-group .card-panel .card-panel-icon[data-v-ec27f13c]{float:left;font-size:48px}.panel-group .card-panel .card-panel-description[data-v-ec27f13c]{float:right;font-weight:700;margin:26px;margin-left:0}.panel-group .card-panel .card-panel-description .card-panel-text[data-v-ec27f13c]{line-height:18px;color:rgba(0,0,0,.45);font-size:16px;margin-bottom:12px}.panel-group .card-panel .card-panel-description .card-panel-num[data-v-ec27f13c]{font-size:20px}@media (max-width:550px){.card-panel-description[data-v-ec27f13c]{display:none}.card-panel-icon-wrapper[data-v-ec27f13c]{float:none!important;width:100%;height:100%;margin:0!important}.card-panel-icon-wrapper .svg-icon[data-v-ec27f13c]{display:block;margin:14px auto!important;float:none!important}}.dashboard-editor-container[data-v-4ac7101a]{padding:32px;position:relative}.dashboard-editor-container .github-corner[data-v-4ac7101a]{position:absolute;top:0;border:0;right:0}.dashboard-editor-container .chart-wrapper[data-v-4ac7101a]{background:#fff;padding:16px 16px 0;margin-bottom:32px}@media (max-width:1024px){.chart-wrapper[data-v-4ac7101a]{padding:8px}}
--------------------------------------------------------------------------------
/dist_backup/static/css/chunk-bcebd8aa.78a33c26.css:
--------------------------------------------------------------------------------
1 | .chart-container[data-v-da4d48fa]{position:relative;width:100%;height:calc(100vh - 84px)}
--------------------------------------------------------------------------------
/dist_backup/static/css/chunk-e8029a4a.5c0a5547.css:
--------------------------------------------------------------------------------
1 | .wrapper-class[data-v-f006624a]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;margin-top:15px}.wrapper-class .el-icon-question[data-v-f006624a]{color:#36a3f7}
--------------------------------------------------------------------------------
/dist_backup/static/css/chunk-e9dba01a.b0fc6a10.css:
--------------------------------------------------------------------------------
1 | .mixin-components-container[data-v-550e716b]{background-color:#f0f2f5;padding:30px;min-height:calc(100vh - 84px)}.component-item[data-v-550e716b]{min-height:100px}.el-select .el-input[data-v-550e716b]{width:130px}.input-with-select .el-input-group__prepend[data-v-550e716b]{background-color:#fff}
--------------------------------------------------------------------------------
/dist_backup/static/fonts/element-icons.535877f5.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/didi/GateKeeper/3c5211ab37040f47c5c9bd236adb06e8c69127d3/dist_backup/static/fonts/element-icons.535877f5.woff
--------------------------------------------------------------------------------
/dist_backup/static/fonts/element-icons.732389de.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/didi/GateKeeper/3c5211ab37040f47c5c9bd236adb06e8c69127d3/dist_backup/static/fonts/element-icons.732389de.ttf
--------------------------------------------------------------------------------
/dist_backup/static/img/401.089007e7.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/didi/GateKeeper/3c5211ab37040f47c5c9bd236adb06e8c69127d3/dist_backup/static/img/401.089007e7.gif
--------------------------------------------------------------------------------
/dist_backup/static/img/404.a57b6f31.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/didi/GateKeeper/3c5211ab37040f47c5c9bd236adb06e8c69127d3/dist_backup/static/img/404.a57b6f31.png
--------------------------------------------------------------------------------
/dist_backup/static/img/404_cloud.0f4bc32b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/didi/GateKeeper/3c5211ab37040f47c5c9bd236adb06e8c69127d3/dist_backup/static/img/404_cloud.0f4bc32b.png
--------------------------------------------------------------------------------
/dist_backup/static/img/double-arrow-left.56942267.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/dist_backup/static/img/logo.e3a14490.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/dist_backup/static/js/chunk-2d230fe7.f069ed37.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d230fe7"],{ef3c:function(e,r,n){"use strict";n.r(r);n("8dee");var t,u,a={created:function(){var e=this.$route,r=e.params,n=e.query,t=r.path;this.$router.replace({path:"/"+t,query:n})},render:function(e){return e()}},c=a,o=n("cba8"),p=Object(o["a"])(c,t,u,!1,null,null,null);r["default"]=p.exports}}]);
--------------------------------------------------------------------------------
/dist_backup/static/js/chunk-2f5ea260.34edaec3.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2f5ea260"],{"1db4":function(t,s,a){"use strict";a.r(s);var c=function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("div",{staticClass:"wscn-http404-container"},[a("div",{staticClass:"wscn-http404"},[t._m(0),a("div",{staticClass:"bullshit"},[a("div",{staticClass:"bullshit__oops"},[t._v("OOPS!")]),t._m(1),a("div",{staticClass:"bullshit__headline"},[t._v(t._s(t.message))]),a("div",{staticClass:"bullshit__info"},[t._v(" Please check that the URL you entered is correct, or click the button below to return to the homepage. ")]),a("a",{staticClass:"bullshit__return-home",attrs:{href:""}},[t._v("Back to home")])])])])},e=[function(){var t=this,s=t.$createElement,c=t._self._c||s;return c("div",{staticClass:"pic-404"},[c("img",{staticClass:"pic-404__parent",attrs:{src:a("a36b"),alt:"404"}}),c("img",{staticClass:"pic-404__child left",attrs:{src:a("26fc"),alt:"404"}}),c("img",{staticClass:"pic-404__child mid",attrs:{src:a("26fc"),alt:"404"}}),c("img",{staticClass:"pic-404__child right",attrs:{src:a("26fc"),alt:"404"}})])},function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("div",{staticClass:"bullshit__info"},[t._v(" All rights reserved "),a("a",{staticStyle:{color:"#20a0ff"},attrs:{href:"https://wallstreetcn.com",target:"_blank"}},[t._v(" wallstreetcn ")])])}],i={name:"Page404",computed:{message:function(){return"The webmaster said that you can not enter this page..."}}},l=i,n=(a("26c2"),a("cba8")),r=Object(n["a"])(l,c,e,!1,null,"c4f16cd2",null);s["default"]=r.exports},"26c2":function(t,s,a){"use strict";a("ff95")},"26fc":function(t,s,a){t.exports=a.p+"static/img/404_cloud.0f4bc32b.png"},a36b:function(t,s,a){t.exports=a.p+"static/img/404.a57b6f31.png"},ff95:function(t,s,a){}}]);
--------------------------------------------------------------------------------
/dist_backup/static/js/chunk-3f238847.dde743ce.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-3f238847"],{"24e2":function(t,a,i){"use strict";i.r(a);var e=function(){var t=this,a=t.$createElement,i=t._self._c||a;return i("div",{staticClass:"errPage-container"},[i("el-button",{staticClass:"pan-back-btn",attrs:{icon:"el-icon-arrow-left"},on:{click:t.back}},[t._v(" 返回 ")]),i("el-row",[i("el-col",{attrs:{span:12}},[i("h1",{staticClass:"text-jumbo text-ginormous"},[t._v(" Oops! ")]),t._v(" gif来源 "),i("a",{attrs:{href:"https://zh.airbnb.com/",target:"_blank"}},[t._v("airbnb")]),t._v(" 页面 "),i("h2",[t._v("你没有权限去该页面")]),i("h6",[t._v("如有不满请联系你领导")]),i("ul",{staticClass:"list-unstyled"},[i("li",[t._v("或者你可以去:")]),i("li",{staticClass:"link-type"},[i("router-link",{attrs:{to:"/dashboard"}},[t._v(" 回首页 ")])],1),i("li",{staticClass:"link-type"},[i("a",{attrs:{href:"https://www.taobao.com/"}},[t._v("随便看看")])]),i("li",[i("a",{attrs:{href:"#"},on:{click:function(a){a.preventDefault(),t.dialogVisible=!0}}},[t._v("点我看图")])])])]),i("el-col",{attrs:{span:12}},[i("img",{attrs:{src:t.errGif,width:"313",height:"428",alt:"Girl has dropped her ice cream."}})])],1),i("el-dialog",{attrs:{visible:t.dialogVisible,title:"随便看"},on:{"update:visible":function(a){t.dialogVisible=a}}},[i("img",{staticClass:"pan-img",attrs:{src:t.ewizardClap}})])],1)},s=[],r=i("cc6c"),c=i.n(r),l={name:"Page401",data:function(){return{errGif:c.a+"?"+ +new Date,ewizardClap:"https://wpimg.wallstcn.com/007ef517-bafd-4066-aae4-6883632d9646",dialogVisible:!1}},methods:{back:function(){this.$route.query.noGoBack?this.$router.push({path:"/dashboard"}):this.$router.go(-1)}}},n=l,o=(i("663b"),i("cba8")),u=Object(o["a"])(n,e,s,!1,null,"61343d02",null);a["default"]=u.exports},"663b":function(t,a,i){"use strict";i("ec97")},cc6c:function(t,a,i){t.exports=i.p+"static/img/401.089007e7.gif"},ec97:function(t,a,i){}}]);
--------------------------------------------------------------------------------
/dist_backup/static/js/chunk-57e15452.3a533841.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-57e15452"],{"69b0":function(n,t){n.exports=Object.is||function(n,t){return n===t?0!==n||1/n===1/t:n!=n&&t!=t}},b829:function(n,t,e){"use strict";e.r(t);e("d91d");var r,i,o={name:"AuthRedirect",created:function(){var n=window.location.search.slice(1);window.localStorage&&(window.localStorage.setItem("x-admin-oauth-code",n),window.close())},render:function(n){return n()}},a=o,c=e("cba8"),u=Object(c["a"])(a,r,i,!1,null,null,null);t["default"]=u.exports},d91d:function(n,t,e){"use strict";var r=e("a86f"),i=e("69b0"),o=e("f417");e("c46f")("search",1,(function(n,t,e,a){return[function(e){var r=n(this),i=void 0==e?void 0:e[t];return void 0!==i?i.call(e,r):new RegExp(e)[t](String(r))},function(n){var t=a(e,n,this);if(t.done)return t.value;var c=r(n),u=String(this),d=c.lastIndex;i(d,0)||(c.lastIndex=0);var l=o(c,u);return i(c.lastIndex,d)||(c.lastIndex=d),null===l?-1:l.index}]}))}}]);
--------------------------------------------------------------------------------
/docker_build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | export GO111MODULE=auto && export GOPROXY=https://goproxy.cn && go mod tidy
3 | GOOS=linux GOARCH=amd64 go build -o ./bin/gatekeeper
4 | docker build -f dockerfile-dashboard -t go-gateteway-dashboard .
5 | docker build -f dockerfile-server -t go-gateteway-server .
--------------------------------------------------------------------------------
/dockerfile-dashboard:
--------------------------------------------------------------------------------
1 | FROM golang
2 |
3 | WORKDIR /go/src/app
4 | COPY . .
5 | #原始方式:直接镜像内打包编译
6 | #RUN export GO111MODULE=auto && export GOPROXY=https://goproxy.cn && go mod tidy
7 | #RUN go build -o ./bin/gatekeeper
8 |
9 | CMD ./bin/gatekeeper -c ./conf/dev/ -p control
--------------------------------------------------------------------------------
/dockerfile-server:
--------------------------------------------------------------------------------
1 | FROM golang
2 |
3 | WORKDIR /go/src/app
4 | COPY . .
5 |
6 | #原始方式:直接镜像内打包编译
7 | #RUN export GO111MODULE=auto && export GOPROXY=https://goproxy.cn && go mod tidy
8 | #RUN go build -o gatekeeper
9 |
10 | CMD ./bin/gatekeeper -c ./conf/dev/ -p control
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/didi/GateKeeper/3c5211ab37040f47c5c9bd236adb06e8c69127d3/favicon.ico
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/didi/gatekeeper
2 |
3 | go 1.16
4 |
5 | require (
6 | git.apache.org/thrift.git v0.13.0
7 | github.com/BurntSushi/toml v0.3.1
8 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
9 | github.com/bitly/go-simplejson v0.5.0
10 | github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
11 | github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff // indirect
12 | github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
13 | github.com/denisenkom/go-mssqldb v0.0.0-20200620013148-b91950f658ec // indirect
14 | github.com/dgrijalva/jwt-go v3.2.0+incompatible
15 | github.com/e421083458/gorm v1.0.1
16 | github.com/e421083458/grpc-proxy v0.2.0
17 | github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 // indirect
18 | github.com/garyburd/redigo v1.6.0
19 | github.com/gin-gonic/contrib v0.0.0-20191209060500-d6e26eeaa607
20 | github.com/gin-gonic/gin v1.7.0
21 | github.com/go-playground/locales v0.13.0
22 | github.com/go-playground/universal-translator v0.17.0
23 | github.com/go-sql-driver/mysql v1.5.0 // indirect
24 | github.com/gorilla/sessions v1.1.3 // indirect
25 | github.com/jinzhu/inflection v1.0.0 // indirect
26 | github.com/jinzhu/now v1.1.1 // indirect
27 | github.com/lib/pq v1.7.1 // indirect
28 | github.com/mattn/go-sqlite3 v1.14.0 // indirect
29 | github.com/mwitkow/grpc-proxy v0.0.0-20181017164139-0f1106ef9c76 // indirect
30 | github.com/pkg/errors v0.9.1
31 | github.com/rs/xid v1.3.0
32 | github.com/smartystreets/goconvey v1.6.4
33 | github.com/spf13/cobra v1.2.1
34 | github.com/spf13/viper v1.8.1
35 | github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14
36 | github.com/swaggo/gin-swagger v1.2.0
37 | github.com/swaggo/swag v1.6.5
38 | github.com/zenazn/goji v1.0.1
39 | golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1
40 | golang.org/x/tools v0.1.5
41 | google.golang.org/grpc v1.38.0
42 | gopkg.in/go-playground/validator.v9 v9.29.0
43 | )
44 |
--------------------------------------------------------------------------------
/golang_common/lib/cmd.go:
--------------------------------------------------------------------------------
1 | package lib
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/pkg/errors"
6 | "github.com/spf13/cobra"
7 | )
8 |
9 | var confPath string
10 | var panelType string
11 | var cmdRun = &cobra.Command{
12 | Use: "run",
13 | Short: "Run a gatekeeper application",
14 | Long: `Run a gatekeeper application by parameter`,
15 | Args: func(cmd *cobra.Command, args []string) error {
16 | panelType = cmd.Flag("panel_type").Value.String()
17 | confPath = cmd.Flag("conf_path").Value.String()
18 | if ok, _ := PathExists(confPath); !ok {
19 | return errors.New("conf_path is not a real dir")
20 | }
21 | if !InArrayString(panelType, []string{"proxy", "control", "both"}) {
22 | return errors.New("panel_type error,choose one from both/proxy/control")
23 | }
24 | return nil
25 | },
26 | Run: func(cmd *cobra.Command, args []string) {
27 | },
28 | }
29 |
30 | func CmdExecute() error {
31 | cmdRun.Flags().StringVarP(&panelType, "panel_type", "p", "", "set panel type like 'both/proxy/control'")
32 | cmdRun.Flags().StringVarP(&confPath, "conf_path", "c", "", "set configuration path like './conf/dev/'")
33 | cmdRun.MarkFlagRequired("panel_type")
34 | cmdRun.MarkFlagRequired("conf_path")
35 | var rootCmd = &cobra.Command{
36 | Use: "",
37 | Short: "Gatekeeper command manager",
38 | CompletionOptions: cobra.CompletionOptions{DisableDefaultCmd: true, DisableNoDescFlag: true, DisableDescriptions: true},
39 | }
40 | rootCmd.AddCommand(cmdRun)
41 | gin.SetMode(gin.ReleaseMode)
42 | return rootCmd.Execute()
43 | }
44 |
45 | func GetCmdConfPath() string {
46 | return confPath
47 | }
48 |
49 | func GetCmdPanelType() string {
50 | return panelType
51 | }
52 |
53 | func SetCmdConfPath(path string) {
54 | confPath = path
55 | }
56 |
57 | func SetCmdPanelType(paneltype string) {
58 | panelType = paneltype
59 | }
60 |
--------------------------------------------------------------------------------
/golang_common/lib/func.go:
--------------------------------------------------------------------------------
1 | package lib
2 |
3 | import (
4 | "crypto/md5"
5 | "encoding/hex"
6 | "net"
7 | "os"
8 | )
9 |
10 | func GetMd5Hash(text string) string {
11 | hasher := md5.New()
12 | hasher.Write([]byte(text))
13 | return hex.EncodeToString(hasher.Sum(nil))
14 | }
15 |
16 | func Encode(data string) (string, error) {
17 | h := md5.New()
18 | _, err := h.Write([]byte(data))
19 | if err != nil {
20 | return "", err
21 | }
22 | return hex.EncodeToString(h.Sum(nil)), nil
23 | }
24 |
25 | func GetLocalIPs() (ips []net.IP) {
26 | interfaceAddr, err := net.InterfaceAddrs()
27 | if err != nil {
28 | return nil
29 | }
30 | for _, address := range interfaceAddr {
31 | ipNet, isValidIpNet := address.(*net.IPNet)
32 | if isValidIpNet && !ipNet.IP.IsLoopback() {
33 | if ipNet.IP.To4() != nil {
34 | ips = append(ips, ipNet.IP)
35 | }
36 | }
37 | }
38 | return ips
39 | }
40 |
41 | func InArrayString(s string, arr []string) bool {
42 | for _, i := range arr {
43 | if i == s {
44 | return true
45 | }
46 | }
47 | return false
48 | }
49 |
50 | func Substr(str string, start int64, end int64) string {
51 | length := int64(len(str))
52 | if start < 0 || start > length {
53 | return ""
54 | }
55 | if end < 0 {
56 | return ""
57 | }
58 | if end > length {
59 | end = length
60 | }
61 | return string(str[start:end])
62 | }
63 |
64 | func PathExists(path string) (bool, error) {
65 | _, err := os.Stat(path)
66 | if err == nil {
67 | return true, nil
68 | }
69 | if os.IsNotExist(err) {
70 | return false, nil
71 | }
72 | return false, err
73 | }
--------------------------------------------------------------------------------
/golang_common/trace/trace_test.go:
--------------------------------------------------------------------------------
1 | package trace
2 |
3 | import (
4 | "context"
5 | "net/http/httptest"
6 | "reflect"
7 | "testing"
8 | )
9 |
10 | func TestGetTraceId(t *testing.T) {
11 | req := httptest.NewRequest("POST", "http://www.test.com", nil)
12 | tracer := New(req)
13 | traceid := tracer.GetTraceId(req)
14 | if len(traceid) <= 0 {
15 | t.Failed()
16 | }
17 | t.Log(traceid)
18 | }
19 |
20 | func TestIsTraceSampleEnabled(t *testing.T) {
21 | req := httptest.NewRequest("POST", "http://www.test.com", nil)
22 | tracer := New(req)
23 | hit := tracer.IsTraceSampleEnabled()
24 | t.Log(hit)
25 | }
26 |
27 | func BenchmarkGetTraceId(b *testing.B) {
28 | req := httptest.NewRequest("POST", "http://www.test.com", nil)
29 | for i := 0; i < b.N; i++ {
30 | tracer := New(req)
31 | tracer.GetTraceId(req)
32 | }
33 | }
34 |
35 | func BenchmarkGetLocalIP(b *testing.B) {
36 | for i := 0; i < b.N; i++ {
37 | getLocalIP()
38 | }
39 | }
40 |
41 | func TestGetCtxTrace(t *testing.T) {
42 | type args struct {
43 | ctx context.Context
44 | }
45 | tests := []struct {
46 | name string
47 | args args
48 | want *Trace
49 | want1 bool
50 | }{
51 | // TODO: Add test cases.
52 | }
53 | for _, tt := range tests {
54 | t.Run(tt.name, func(t *testing.T) {
55 | got, got1 := GetCtxTrace(tt.args.ctx)
56 | if !reflect.DeepEqual(got, tt.want) {
57 | t.Errorf("GetCtxTrace() got = %v, want %v", got, tt.want)
58 | }
59 | if got1 != tt.want1 {
60 | t.Errorf("GetCtxTrace() got1 = %v, want %v", got1, tt.want1)
61 | }
62 | })
63 | }
64 | }
65 |
66 | func TestNewWithMap(t *testing.T) {
67 | type args struct {
68 | m map[string]string
69 | }
70 | tests := []struct {
71 | name string
72 | args args
73 | }{
74 | // TODO: Add test cases.
75 | {
76 | name: "test1",
77 | args: args {
78 | m: map[string]string{
79 | "didi-header-rid":"1234",
80 | DIDI_HEADER_SPANID:"3435",
81 | },
82 | },
83 | },
84 | }
85 | for _, tt := range tests {
86 | t.Run(tt.name, func(t *testing.T) {
87 | if gotTrace := NewWithMap(tt.args.m); gotTrace != nil {
88 | t.Logf("NewWithMap() = %v", gotTrace)
89 | }
90 | })
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/golang_common/zerolog/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled Object files, Static and Dynamic libs (Shared Objects)
2 | *.o
3 | *.a
4 | *.so
5 |
6 | # Folders
7 | _obj
8 | _test
9 | tmp
10 |
11 | # Architecture specific extensions/prefixes
12 | *.[568vq]
13 | [568vq].out
14 |
15 | *.cgo1.go
16 | *.cgo2.c
17 | _cgo_defun.c
18 | _cgo_gotypes.go
19 | _cgo_export.*
20 |
21 | _testmain.go
22 |
23 | *.exe
24 | *.test
25 | *.prof
26 | .*
27 | !/.gitignore
--------------------------------------------------------------------------------
/golang_common/zerolog/CNAME:
--------------------------------------------------------------------------------
1 | zerolog.io
--------------------------------------------------------------------------------
/golang_common/zerolog/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Olivier Poitrey
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/golang_common/zerolog/_config.yml:
--------------------------------------------------------------------------------
1 | remote_theme: rs/gh-readme
2 |
--------------------------------------------------------------------------------
/golang_common/zerolog/array_json_test.go:
--------------------------------------------------------------------------------
1 | // +build json_log
2 |
3 | package zerolog
4 |
5 | import (
6 | "net"
7 | "testing"
8 | "time"
9 | )
10 |
11 | func TestArray(t *testing.T) {
12 | a := Arr().
13 | Bool(true).
14 | Int(1).
15 | Int8(2).
16 | Int16(3).
17 | Int32(4).
18 | Int64(5).
19 | Uint(6).
20 | Uint8(7).
21 | Uint16(8).
22 | Uint32(9).
23 | Uint64(10).
24 | Float32(11.98122).
25 | Float64(12.987654321).
26 | Str("a").
27 | Bytes([]byte("b")).
28 | Hex([]byte{0x1f}).
29 | Time(time.Time{}).
30 | IPAddr(net.IP{192, 168, 0, 10}).
31 | Dur(0)
32 | want := `[true,1,2,3,4,5,6,7,8,9,10,11.98122,12.987654321,"a","b","1f","0001-01-01T00:00:00Z","192.168.0.10",0]`
33 | if got := decodeObjectToStr(a.write([]byte{})); got != want {
34 | t.Errorf("Array.write()\ngot: %s\nwant: %s", got, want)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/golang_common/zerolog/array_test.go:
--------------------------------------------------------------------------------
1 | package zerolog
2 |
3 | import (
4 | "net"
5 | "testing"
6 | "time"
7 | )
8 |
9 | func TestArray(t *testing.T) {
10 | a := Arr().
11 | Bool(true).
12 | Int(1).
13 | Int8(2).
14 | Int16(3).
15 | Int32(4).
16 | Int64(5).
17 | Uint(6).
18 | Uint8(7).
19 | Uint16(8).
20 | Uint32(9).
21 | Uint64(10).
22 | Float32(11.98122).
23 | Float64(12.987654321).
24 | Str("a").
25 | Bytes([]byte("b")).
26 | Hex([]byte{0x1f}).
27 | Time(time.Time{}).
28 | IPAddr(net.IP{192, 168, 0, 10}).
29 | Dur(0)
30 | want := `[true,1,2,3,4,5,6,7,8,9,10,11.98122,12.987654321,a,b,1f,0001-01-01T00:00:00Z,192.168.0.10,0]`
31 | if got := decodeObjectToStr(a.write([]byte{})); got != want {
32 | t.Errorf("Array.write()\ngot: %s\nwant: %s", got, want)
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/golang_common/zerolog/ctx.go:
--------------------------------------------------------------------------------
1 | package zerolog
2 |
3 | import (
4 | "context"
5 | )
6 |
7 | var disabledLogger *Logger
8 |
9 | func init() {
10 | l := Nop()
11 | disabledLogger = &l
12 | }
13 |
14 | type ctxKey struct{}
15 |
16 | // WithContext returns a copy of ctx with l associated. If an instance of Logger
17 | // is already in the context, the context is not updated.
18 | //
19 | // For instance, to add a field to an existing logger in the context, use this
20 | // notation:
21 | //
22 | // ctx := r.Context()
23 | // l := zerolog.Ctx(ctx)
24 | // l.UpdateContext(func(c Context) Context {
25 | // return c.Str("bar", "baz")
26 | // })
27 | func (l *Logger) WithContext(ctx context.Context) context.Context {
28 | if lp, ok := ctx.Value(ctxKey{}).(*Logger); ok {
29 | if lp == l {
30 | // Do not store same logger.
31 | return ctx
32 | }
33 | } else if l.level == Disabled {
34 | // Do not store disabled logger.
35 | return ctx
36 | }
37 | return context.WithValue(ctx, ctxKey{}, l)
38 | }
39 |
40 | // Ctx returns the Logger associated with the ctx. If no logger
41 | // is associated, a disabled logger is returned.
42 | func Ctx(ctx context.Context) *Logger {
43 | if l, ok := ctx.Value(ctxKey{}).(*Logger); ok {
44 | return l
45 | }
46 | return disabledLogger
47 | }
48 |
--------------------------------------------------------------------------------
/golang_common/zerolog/ctx_test.go:
--------------------------------------------------------------------------------
1 | package zerolog
2 |
3 | import (
4 | "context"
5 | "io/ioutil"
6 | "reflect"
7 | "testing"
8 | )
9 |
10 | func TestCtx(t *testing.T) {
11 | log := New(ioutil.Discard)
12 | ctx := log.WithContext(context.Background())
13 | log2 := Ctx(ctx)
14 | if !reflect.DeepEqual(log, *log2) {
15 | t.Error("Ctx did not return the expected logger")
16 | }
17 |
18 | // update
19 | log = log.Level(InfoLevel)
20 | ctx = log.WithContext(ctx)
21 | log2 = Ctx(ctx)
22 | if !reflect.DeepEqual(log, *log2) {
23 | t.Error("Ctx did not return the expected logger")
24 | }
25 |
26 | log2 = Ctx(context.Background())
27 | if log2 != disabledLogger {
28 | t.Error("Ctx did not return the expected logger")
29 | }
30 | }
31 |
32 | func TestCtxDisabled(t *testing.T) {
33 | dl := New(ioutil.Discard).Level(Disabled)
34 | ctx := dl.WithContext(context.Background())
35 | if ctx != context.Background() {
36 | t.Error("WithContext stored a disabled logger")
37 | }
38 |
39 | l := New(ioutil.Discard).With().Str("foo", "bar").Logger()
40 | ctx = l.WithContext(ctx)
41 | if Ctx(ctx) != &l {
42 | t.Error("WithContext did not store logger")
43 | }
44 |
45 | l.UpdateContext(func(c Context) Context {
46 | return c.Str("bar", "baz")
47 | })
48 | ctx = l.WithContext(ctx)
49 | if Ctx(ctx) != &l {
50 | t.Error("WithContext did not store updated logger")
51 | }
52 |
53 | l = l.Level(DebugLevel)
54 | ctx = l.WithContext(ctx)
55 | if Ctx(ctx) != &l {
56 | t.Error("WithContext did not store copied logger")
57 | }
58 |
59 | ctx = dl.WithContext(ctx)
60 | if Ctx(ctx) != &dl {
61 | t.Error("WithContext did not overide logger with a disabled logger")
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/golang_common/zerolog/ddlog/log.go:
--------------------------------------------------------------------------------
1 | package ddlog
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/didi/gatekeeper/golang_common/zerolog"
7 | )
8 |
9 | var (
10 | //Logger is defualt log ,and print to stdout, if want format context, use RegisterContextFormat
11 | Logger *DiLogHandle
12 | )
13 |
14 | func init() {
15 | diLogger := zerolog.New(zerolog.NewStdoutWriter())
16 | diLogger = diLogger.Level(zerolog.DebugLevel)
17 | Logger = &DiLogHandle{Logger: diLogger}
18 | }
19 |
20 | func Debugf(ctx context.Context, tag string, format string, args ...interface{}) {
21 | Logger.Debugf(ctx, tag, format, args...)
22 | }
23 |
24 | func Debug(args ...interface{}) {
25 | Logger.Debug(args...)
26 | }
27 |
28 | func Infof(ctx context.Context, tag string, format string, args ...interface{}) {
29 | Logger.Infof(ctx, tag, format, args...)
30 | }
31 |
32 | func Info(args ...interface{}) {
33 | Logger.Info(args...)
34 | }
35 |
36 | func Warnf(ctx context.Context, tag string, format string, args ...interface{}) {
37 | Logger.Warnf(ctx, tag, format, args...)
38 | }
39 |
40 | func Warn(args ...interface{}) {
41 | Logger.Warn(args...)
42 | }
43 |
44 | func Errorf(ctx context.Context, tag string, format string, args ...interface{}) {
45 | Logger.Errorf(ctx, tag, format, args...)
46 | }
47 |
48 | func Error(args ...interface{}) {
49 | Logger.Error(args...)
50 | }
51 |
52 | func Fatalf(ctx context.Context, tag string, format string, args ...interface{}) {
53 | Logger.Fatalf(ctx, tag, format, args...)
54 | }
55 |
56 | func Fatal(args ...interface{}) {
57 | Logger.Fatal(args...)
58 | }
59 |
--------------------------------------------------------------------------------
/golang_common/zerolog/diode/diode_example_test.go:
--------------------------------------------------------------------------------
1 | // +build !binary_log
2 |
3 | package diode_test
4 |
5 | import (
6 | "fmt"
7 | "os"
8 |
9 | "github.com/didi/gatekeeper/golang_common/zerolog"
10 | "github.com/didi/gatekeeper/golang_common/zerolog/diode"
11 | )
12 |
13 | func ExampleNewWriter() {
14 | w := diode.NewWriter(os.Stdout, 1000, 0, func(missed int) {
15 | fmt.Printf("Dropped %d messages\n", missed)
16 | })
17 | log := zerolog.New(w)
18 | log.Print("test")
19 |
20 | w.Close()
21 |
22 | // Output: {"level":"debug","message":"test"}
23 | }
24 |
--------------------------------------------------------------------------------
/golang_common/zerolog/diode/diode_test.go:
--------------------------------------------------------------------------------
1 | package diode_test
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "io/ioutil"
7 | "log"
8 | "os"
9 | "testing"
10 | "time"
11 |
12 | "github.com/didi/gatekeeper/golang_common/zerolog"
13 | "github.com/didi/gatekeeper/golang_common/zerolog/diode"
14 | "github.com/didi/gatekeeper/golang_common/zerolog/internal/cbor"
15 | )
16 |
17 | func TestNewWriter(t *testing.T) {
18 | buf := bytes.Buffer{}
19 | w := diode.NewWriter(&buf, 1000, 0, func(missed int) {
20 | fmt.Printf("Dropped %d messages\n", missed)
21 | })
22 | log := zerolog.New(w)
23 | log.Print("test")
24 |
25 | w.Close()
26 | want := "{\"level\":\"debug\",\"message\":\"test\"}\n"
27 | got := cbor.DecodeIfBinaryToString(buf.Bytes())
28 | if got != want {
29 | t.Errorf("Diode New Writer Test failed. got:%s, want:%s!", got, want)
30 | }
31 | }
32 |
33 | func Benchmark(b *testing.B) {
34 | log.SetOutput(ioutil.Discard)
35 | defer log.SetOutput(os.Stderr)
36 | benchs := map[string]time.Duration{
37 | "Waiter": 0,
38 | "Pooler": 10 * time.Millisecond,
39 | }
40 | for name, interval := range benchs {
41 | b.Run(name, func(b *testing.B) {
42 | w := diode.NewWriter(ioutil.Discard, 100000, interval, nil)
43 | log := zerolog.New(w)
44 | defer w.Close()
45 |
46 | b.SetParallelism(1000)
47 | b.RunParallel(func(pb *testing.PB) {
48 | for pb.Next() {
49 | log.Print("test")
50 | }
51 | })
52 | })
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/golang_common/zerolog/diode/internal/diodes/README:
--------------------------------------------------------------------------------
1 | Copied from https://github.com/cloudfoundry/go-diodes to avoid test dependencies.
2 |
--------------------------------------------------------------------------------
/golang_common/zerolog/diode/internal/diodes/poller.go:
--------------------------------------------------------------------------------
1 | package diodes
2 |
3 | import (
4 | "context"
5 | "time"
6 | )
7 |
8 | // Diode is any implementation of a diode.
9 | type Diode interface {
10 | Set(GenericDataType)
11 | TryNext() (GenericDataType, bool)
12 | }
13 |
14 | // Poller will poll a diode until a value is available.
15 | type Poller struct {
16 | Diode
17 | interval time.Duration
18 | ctx context.Context
19 | }
20 |
21 | // PollerConfigOption can be used to setup the poller.
22 | type PollerConfigOption func(*Poller)
23 |
24 | // WithPollingInterval sets the interval at which the diode is queried
25 | // for new data. The default is 10ms.
26 | func WithPollingInterval(interval time.Duration) PollerConfigOption {
27 | return PollerConfigOption(func(c *Poller) {
28 | c.interval = interval
29 | })
30 | }
31 |
32 | // WithPollingContext sets the context to cancel any retrieval (Next()). It
33 | // will not change any results for adding data (Set()). Default is
34 | // context.Background().
35 | func WithPollingContext(ctx context.Context) PollerConfigOption {
36 | return PollerConfigOption(func(c *Poller) {
37 | c.ctx = ctx
38 | })
39 | }
40 |
41 | // NewPoller returns a new Poller that wraps the given diode.
42 | func NewPoller(d Diode, opts ...PollerConfigOption) *Poller {
43 | p := &Poller{
44 | Diode: d,
45 | interval: 10 * time.Millisecond,
46 | ctx: context.Background(),
47 | }
48 |
49 | for _, o := range opts {
50 | o(p)
51 | }
52 |
53 | return p
54 | }
55 |
56 | // Next polls the diode until data is available or until the context is done.
57 | // If the context is done, then nil will be returned.
58 | func (p *Poller) Next() GenericDataType {
59 | for {
60 | data, ok := p.Diode.TryNext()
61 | if !ok {
62 | if p.isDone() {
63 | return nil
64 | }
65 |
66 | time.Sleep(p.interval)
67 | continue
68 | }
69 | return data
70 | }
71 | }
72 |
73 | func (p *Poller) isDone() bool {
74 | select {
75 | case <-p.ctx.Done():
76 | return true
77 | default:
78 | return false
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/golang_common/zerolog/diode/internal/diodes/waiter.go:
--------------------------------------------------------------------------------
1 | package diodes
2 |
3 | import (
4 | "context"
5 | "sync"
6 | )
7 |
8 | // Waiter will use a conditional mutex to alert the reader to when data is
9 | // available.
10 | type Waiter struct {
11 | Diode
12 | mu sync.Mutex
13 | c *sync.Cond
14 | ctx context.Context
15 | }
16 |
17 | // WaiterConfigOption can be used to setup the waiter.
18 | type WaiterConfigOption func(*Waiter)
19 |
20 | // WithWaiterContext sets the context to cancel any retrieval (Next()). It
21 | // will not change any results for adding data (Set()). Default is
22 | // context.Background().
23 | func WithWaiterContext(ctx context.Context) WaiterConfigOption {
24 | return WaiterConfigOption(func(c *Waiter) {
25 | c.ctx = ctx
26 | })
27 | }
28 |
29 | // NewWaiter returns a new Waiter that wraps the given diode.
30 | func NewWaiter(d Diode, opts ...WaiterConfigOption) *Waiter {
31 | w := new(Waiter)
32 | w.Diode = d
33 | w.c = sync.NewCond(&w.mu)
34 | w.ctx = context.Background()
35 |
36 | for _, opt := range opts {
37 | opt(w)
38 | }
39 |
40 | go func() {
41 | <-w.ctx.Done()
42 | w.c.Broadcast()
43 | }()
44 |
45 | return w
46 | }
47 |
48 | // Set invokes the wrapped diode's Set with the given data and uses Broadcast
49 | // to wake up any readers.
50 | func (w *Waiter) Set(data GenericDataType) {
51 | w.Diode.Set(data)
52 | w.c.Broadcast()
53 | }
54 |
55 | // Next returns the next data point on the wrapped diode. If there is not any
56 | // new data, it will Wait for set to be called or the context to be done.
57 | // If the context is done, then nil will be returned.
58 | func (w *Waiter) Next() GenericDataType {
59 | w.mu.Lock()
60 | defer w.mu.Unlock()
61 |
62 | for {
63 | data, ok := w.Diode.TryNext()
64 | if !ok {
65 | if w.isDone() {
66 | return nil
67 | }
68 |
69 | w.c.Wait()
70 | continue
71 | }
72 | return data
73 | }
74 | }
75 |
76 | func (w *Waiter) isDone() bool {
77 | select {
78 | case <-w.ctx.Done():
79 | return true
80 | default:
81 | return false
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/golang_common/zerolog/elevate/cr.yml:
--------------------------------------------------------------------------------
1 | reviewers: weijingwu,shenjun
2 | owners: weijingwu,shenjun
3 | strategy: default
4 | lint:
5 | force: false
6 | language:
7 | go:
8 | standard: golint
9 | exclude:
10 | - (^vendor/)
11 |
12 |
--------------------------------------------------------------------------------
/golang_common/zerolog/encoder_cbor.go:
--------------------------------------------------------------------------------
1 | // +build binary_log
2 |
3 | package zerolog
4 |
5 | // This file contains bindings to do binary encoding.
6 |
7 | import (
8 | "github.com/didi/gatekeeper/golang_common/zerolog/internal/cbor"
9 | )
10 |
11 | var (
12 | _ encoder = (*cbor.Encoder)(nil)
13 |
14 | enc = cbor.Encoder{}
15 | )
16 |
17 | func appendJSON(dst []byte, j []byte) []byte {
18 | return cbor.AppendEmbeddedJSON(dst, j)
19 | }
20 |
21 | // decodeIfBinaryToString - converts a binary formatted log msg to a
22 | // JSON formatted String Log message.
23 | func decodeIfBinaryToString(in []byte) string {
24 | return cbor.DecodeIfBinaryToString(in)
25 | }
26 |
27 | func decodeObjectToStr(in []byte) string {
28 | return cbor.DecodeObjectToStr(in)
29 | }
30 |
31 | // decodeIfBinaryToBytes - converts a binary formatted log msg to a
32 | // JSON formatted Bytes Log message.
33 | func decodeIfBinaryToBytes(in []byte) []byte {
34 | return cbor.DecodeIfBinaryToBytes(in)
35 | }
36 |
--------------------------------------------------------------------------------
/golang_common/zerolog/encoder_console.go:
--------------------------------------------------------------------------------
1 | package zerolog
2 |
3 | // encoder_json.go file contains bindings to generate
4 | // JSON encoded byte stream.
5 |
6 | import (
7 | "os"
8 |
9 | "github.com/didi/gatekeeper/golang_common/zerolog/internal/console"
10 | )
11 |
12 | var (
13 | cwd, _ = os.Getwd()
14 | _ encoder = (*console.Encoder)(nil)
15 |
16 | enc = console.Encoder{}
17 | )
18 |
19 | func appendJSON(dst []byte, j []byte) []byte {
20 | return append(dst, j...)
21 | }
22 |
23 | func decodeIfBinaryToString(in []byte) string {
24 | return string(in)
25 | }
26 |
27 | func decodeObjectToStr(in []byte) string {
28 | return string(in)
29 | }
30 |
31 | func decodeIfBinaryToBytes(in []byte) []byte {
32 | return in
33 | }
34 |
--------------------------------------------------------------------------------
/golang_common/zerolog/encoder_json.go:
--------------------------------------------------------------------------------
1 | // +build json_log
2 |
3 | package zerolog
4 |
5 | // encoder_json.go file contains bindings to generate
6 | // JSON encoded byte stream.
7 |
8 | import (
9 | "github.com/didi/gatekeeper/golang_common/zerolog/internal/json"
10 | )
11 |
12 | var (
13 | _ encoder = (*json.Encoder)(nil)
14 |
15 | enc = json.Encoder{}
16 | )
17 |
18 | func appendJSON(dst []byte, j []byte) []byte {
19 | return append(dst, j...)
20 | }
21 |
22 | func decodeIfBinaryToString(in []byte) string {
23 | return string(in)
24 | }
25 |
26 | func decodeObjectToStr(in []byte) string {
27 | return string(in)
28 | }
29 |
30 | func decodeIfBinaryToBytes(in []byte) []byte {
31 | return in
32 | }
33 |
--------------------------------------------------------------------------------
/golang_common/zerolog/hook.go:
--------------------------------------------------------------------------------
1 | package zerolog
2 |
3 | // Hook defines an interface to a log hook.
4 | type Hook interface {
5 | // Run runs the hook with the event.
6 | Run(e *Event, level Level, message string)
7 | }
8 |
9 | // HookFunc is an adaptor to allow the use of an ordinary function
10 | // as a Hook.
11 | type HookFunc func(e *Event, level Level, message string)
12 |
13 | // Run implements the Hook interface.
14 | func (h HookFunc) Run(e *Event, level Level, message string) {
15 | h(e, level, message)
16 | }
17 |
18 | // LevelHook applies a different hook for each level.
19 | type LevelHook struct {
20 | NoLevelHook, DebugHook, InfoHook, WarnHook, ErrorHook, FatalHook, PanicHook Hook
21 | }
22 |
23 | // Run implements the Hook interface.
24 | func (h LevelHook) Run(e *Event, level Level, message string) {
25 | switch level {
26 | case DebugLevel:
27 | if h.DebugHook != nil {
28 | h.DebugHook.Run(e, level, message)
29 | }
30 | case InfoLevel:
31 | if h.InfoHook != nil {
32 | h.InfoHook.Run(e, level, message)
33 | }
34 | case WarnLevel:
35 | if h.WarnHook != nil {
36 | h.WarnHook.Run(e, level, message)
37 | }
38 | case ErrorLevel:
39 | if h.ErrorHook != nil {
40 | h.ErrorHook.Run(e, level, message)
41 | }
42 | case FatalLevel:
43 | if h.FatalHook != nil {
44 | h.FatalHook.Run(e, level, message)
45 | }
46 | case PanicLevel:
47 | if h.PanicHook != nil {
48 | h.PanicHook.Run(e, level, message)
49 | }
50 | case NoLevel:
51 | if h.NoLevelHook != nil {
52 | h.NoLevelHook.Run(e, level, message)
53 | }
54 | }
55 | }
56 |
57 | // NewLevelHook returns a new LevelHook.
58 | func NewLevelHook() LevelHook {
59 | return LevelHook{}
60 | }
61 |
--------------------------------------------------------------------------------
/golang_common/zerolog/internal/cbor/base.go:
--------------------------------------------------------------------------------
1 | package cbor
2 |
3 | type Encoder struct{}
4 |
5 | // AppendKey adds a key (string) to the binary encoded log message
6 | func (e Encoder) AppendKey(dst []byte, key string) []byte {
7 | if len(dst) < 1 {
8 | dst = e.AppendBeginMarker(dst)
9 | }
10 | return e.AppendString(dst, key)
11 | }
--------------------------------------------------------------------------------
/golang_common/zerolog/internal/cbor/examples/genLog.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "compress/zlib"
5 | "flag"
6 | "io"
7 | "log"
8 | "os"
9 | "time"
10 |
11 | "github.com/didi/gatekeeper/golang_common/zerolog"
12 | )
13 |
14 | func writeLog(fname string, count int, useCompress bool) {
15 | opFile := os.Stdout
16 | if fname != "" {
17 | fil, _ := os.Create(fname)
18 | opFile = fil
19 | defer func() {
20 | if err := fil.Close(); err != nil {
21 | log.Fatal(err)
22 | }
23 | }()
24 | }
25 |
26 | var f io.WriteCloser = opFile
27 | if useCompress {
28 | f = zlib.NewWriter(f)
29 | defer func() {
30 | if err := f.Close(); err != nil {
31 | log.Fatal(err)
32 | }
33 | }()
34 |
35 | }
36 |
37 | zerolog.TimestampFunc = func() time.Time { return time.Now().Round(time.Second) }
38 | log := zerolog.New(f).With().
39 | Timestamp().
40 | Logger()
41 | for i := 0; i < count; i++ {
42 | log.Error().
43 | Int("Fault", 41650+i).Msg("Some Message")
44 | }
45 | }
46 |
47 | func main() {
48 | outFile := flag.String("out", "", "Output File to which logs will be written to (WILL overwrite if already present).")
49 | numLogs := flag.Int("num", 10, "Number of log messages to generate.")
50 | doCompress := flag.Bool("compress", false, "Enable inline compressed writer")
51 |
52 | flag.Parse()
53 |
54 | writeLog(*outFile, *numLogs, *doCompress)
55 | }
56 |
--------------------------------------------------------------------------------
/golang_common/zerolog/internal/cbor/examples/makefile:
--------------------------------------------------------------------------------
1 | all: genLogJSON genLogCBOR
2 |
3 | genLogJSON: genLog.go
4 | go build -o genLogJSON genLog.go
5 |
6 | genLogCBOR: genLog.go
7 | go build -tags binary_log -o genLogCBOR genLog.go
8 |
9 | clean:
10 | rm -f genLogJSON genLogCBOR
11 |
--------------------------------------------------------------------------------
/golang_common/zerolog/internal/cbor/string.go:
--------------------------------------------------------------------------------
1 | package cbor
2 |
3 | // AppendStrings encodes and adds an array of strings to the dst byte array.
4 | func (e Encoder) AppendStrings(dst []byte, vals []string) []byte {
5 | major := majorTypeArray
6 | l := len(vals)
7 | if l <= additionalMax {
8 | lb := byte(l)
9 | dst = append(dst, byte(major|lb))
10 | } else {
11 | dst = appendCborTypePrefix(dst, major, uint64(l))
12 | }
13 | for _, v := range vals {
14 | dst = e.AppendString(dst, v)
15 | }
16 | return dst
17 | }
18 |
19 | // AppendString encodes and adds a string to the dst byte array.
20 | func (Encoder) AppendString(dst []byte, s string) []byte {
21 | major := majorTypeUtf8String
22 |
23 | l := len(s)
24 | if l <= additionalMax {
25 | lb := byte(l)
26 | dst = append(dst, byte(major|lb))
27 | } else {
28 | dst = appendCborTypePrefix(dst, majorTypeUtf8String, uint64(l))
29 | }
30 | return append(dst, s...)
31 | }
32 |
33 | // AppendBytes encodes and adds an array of bytes to the dst byte array.
34 | func (Encoder) AppendBytes(dst, s []byte) []byte {
35 | major := majorTypeByteString
36 |
37 | l := len(s)
38 | if l <= additionalMax {
39 | lb := byte(l)
40 | dst = append(dst, byte(major|lb))
41 | } else {
42 | dst = appendCborTypePrefix(dst, major, uint64(l))
43 | }
44 | return append(dst, s...)
45 | }
46 |
47 | // AppendEmbeddedJSON adds a tag and embeds input JSON as such.
48 | func AppendEmbeddedJSON(dst, s []byte) []byte {
49 | major := majorTypeTags
50 | minor := additionalTypeEmbeddedJSON
51 |
52 | // Append the TAG to indicate this is Embedded JSON.
53 | dst = append(dst, byte(major|additionalTypeIntUint16))
54 | dst = append(dst, byte(minor>>8))
55 | dst = append(dst, byte(minor&0xff))
56 |
57 | // Append the JSON Object as Byte String.
58 | major = majorTypeByteString
59 |
60 | l := len(s)
61 | if l <= additionalMax {
62 | lb := byte(l)
63 | dst = append(dst, byte(major|lb))
64 | } else {
65 | dst = appendCborTypePrefix(dst, major, uint64(l))
66 | }
67 | return append(dst, s...)
68 | }
69 |
--------------------------------------------------------------------------------
/golang_common/zerolog/internal/console/base.go:
--------------------------------------------------------------------------------
1 | package console
2 |
3 | type Encoder struct{}
4 |
5 | // AppendKey appends a new key to the output JSON.
6 | func (e Encoder) AppendKey(dst []byte, key string) []byte {
7 |
8 | if len(dst) > 1 {
9 | dst = append(dst, []byte("||")...)
10 | }
11 | if key != "" {
12 | dst = e.AppendString(dst, key+"=")
13 | }
14 |
15 | return dst
16 | }
17 |
--------------------------------------------------------------------------------
/golang_common/zerolog/internal/json/base.go:
--------------------------------------------------------------------------------
1 | package json
2 |
3 | type Encoder struct{}
4 |
5 | // AppendKey appends a new key to the output JSON.
6 | func (e Encoder) AppendKey(dst []byte, key string) []byte {
7 | if len(dst) > 1 && dst[len(dst)-1] != '{' {
8 | dst = append(dst, ',')
9 | }
10 | dst = e.AppendString(dst, key)
11 | return append(dst, ':')
12 | }
--------------------------------------------------------------------------------
/golang_common/zerolog/journald/journald_test.go:
--------------------------------------------------------------------------------
1 | // +build !windows
2 |
3 | package journald_test
4 |
5 | import "github.com/didi/gatekeeper/golang_common/zerolog"
6 | import "github.com/didi/gatekeeper/golang_common/zerolog/journald"
7 |
8 | func ExampleNewJournalDWriter() {
9 | log := zerolog.New(journald.NewJournalDWriter())
10 | log.Info().Str("foo", "bar").Uint64("small", 123).Float64("float", 3.14).Uint64("big", 1152921504606846976).Msg("Journal Test")
11 | // Output:
12 | }
13 |
14 | /*
15 |
16 | There is no automated way to verify the output - since the output is sent
17 | to journald process and method to retrieve is journalctl. Will find a way
18 | to automate the process and fix this test.
19 |
20 | $ journalctl -o verbose -f
21 |
22 | Thu 2018-04-26 22:30:20.768136 PDT [s=3284d695bde946e4b5017c77a399237f;i=329f0;b=98c0dca0debc4b98a5b9534e910e7dd6;m=7a702e35dd4;t=56acdccd2ed0a;x=4690034cf0348614]
23 | PRIORITY=6
24 | _AUDIT_LOGINUID=1000
25 | _BOOT_ID=98c0dca0debc4b98a5b9534e910e7dd6
26 | _MACHINE_ID=926ed67eb4744580948de70fb474975e
27 | _HOSTNAME=sprint
28 | _UID=1000
29 | _GID=1000
30 | _CAP_EFFECTIVE=0
31 | _SYSTEMD_SLICE=-.slice
32 | _TRANSPORT=journal
33 | _SYSTEMD_CGROUP=/
34 | _AUDIT_SESSION=2945
35 | MESSAGE=Journal Test
36 | FOO=bar
37 | BIG=1152921504606846976
38 | _COMM=journald.test
39 | SMALL=123
40 | FLOAT=3.14
41 | JSON={"level":"info","foo":"bar","small":123,"float":3.14,"big":1152921504606846976,"message":"Journal Test"}
42 | _PID=27103
43 | _SOURCE_REALTIME_TIMESTAMP=1524807020768136
44 | */
45 |
--------------------------------------------------------------------------------
/golang_common/zerolog/pretty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/didi/GateKeeper/3c5211ab37040f47c5c9bd236adb06e8c69127d3/golang_common/zerolog/pretty.png
--------------------------------------------------------------------------------
/golang_common/zerolog/sampler_test.go:
--------------------------------------------------------------------------------
1 | // +build binary_log
2 |
3 | package zerolog
4 |
5 | import (
6 | "testing"
7 | "time"
8 | )
9 |
10 | var samplers = []struct {
11 | name string
12 | sampler func() Sampler
13 | total int
14 | wantMin int
15 | wantMax int
16 | }{
17 | {
18 | "BasicSampler_1",
19 | func() Sampler {
20 | return &BasicSampler{N: 1}
21 | },
22 | 100, 100, 100,
23 | },
24 | {
25 | "BasicSampler_5",
26 | func() Sampler {
27 | return &BasicSampler{N: 5}
28 | },
29 | 100, 20, 20,
30 | },
31 | {
32 | "RandomSampler",
33 | func() Sampler {
34 | return RandomSampler(5)
35 | },
36 | 100, 10, 30,
37 | },
38 | {
39 | "BurstSampler",
40 | func() Sampler {
41 | return &BurstSampler{Burst: 20, Period: time.Second}
42 | },
43 | 100, 20, 20,
44 | },
45 | {
46 | "BurstSamplerNext",
47 | func() Sampler {
48 | return &BurstSampler{Burst: 20, Period: time.Second, NextSampler: &BasicSampler{N: 5}}
49 | },
50 | 120, 40, 40,
51 | },
52 | }
53 |
54 | func TestSamplers(t *testing.T) {
55 | for i := range samplers {
56 | s := samplers[i]
57 | t.Run(s.name, func(t *testing.T) {
58 | sampler := s.sampler()
59 | got := 0
60 | for t := s.total; t > 0; t-- {
61 | if sampler.Sample(0) {
62 | got++
63 | }
64 | }
65 | if got < s.wantMin || got > s.wantMax {
66 | t.Errorf("%s.Sample(0) == true %d on %d, want [%d, %d]", s.name, got, s.total, s.wantMin, s.wantMax)
67 | }
68 | })
69 | }
70 | }
71 |
72 | func BenchmarkSamplers(b *testing.B) {
73 | for i := range samplers {
74 | s := samplers[i]
75 | b.Run(s.name, func(b *testing.B) {
76 | sampler := s.sampler()
77 | b.RunParallel(func(pb *testing.PB) {
78 | for pb.Next() {
79 | sampler.Sample(0)
80 | }
81 | })
82 | })
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/golang_common/zerolog/stdout_write.go:
--------------------------------------------------------------------------------
1 | package zerolog
2 |
3 | import (
4 | "os"
5 | )
6 |
7 | type StdoutWriter struct {
8 | AccessWriter
9 | }
10 |
11 | // NewStdoutWriter will write to stdout.
12 | func NewStdoutWriter(options ...Option) *StdoutWriter {
13 | w := AccessWriter{}
14 |
15 | for _, opt := range options {
16 | opt(&w)
17 | }
18 |
19 | w.FileOut = os.Stdout
20 | return &StdoutWriter{w}
21 | }
22 |
23 | func (w *StdoutWriter) WriteLevel(l Level, p []byte) (n int, err error) {
24 |
25 | return w.Write(p)
26 | }
27 |
--------------------------------------------------------------------------------
/golang_common/zerolog/syslog.go:
--------------------------------------------------------------------------------
1 | // +build !windows
2 | // +build !binary_log
3 |
4 | package zerolog
5 |
6 | import (
7 | "io"
8 | )
9 |
10 | // SyslogWriter is an interface matching a syslog.Writer struct.
11 | type SyslogWriter interface {
12 | io.Writer
13 | Debug(m string) error
14 | Info(m string) error
15 | Warning(m string) error
16 | Err(m string) error
17 | Emerg(m string) error
18 | Crit(m string) error
19 | }
20 |
21 | type syslogWriter struct {
22 | w SyslogWriter
23 | }
24 |
25 | // SyslogLevelWriter wraps a SyslogWriter and call the right syslog level
26 | // method matching the zerolog level.
27 | func SyslogLevelWriter(w SyslogWriter) LevelWriter {
28 | return syslogWriter{w}
29 | }
30 |
31 | func (sw syslogWriter) Write(p []byte) (n int, err error) {
32 | return sw.w.Write(p)
33 | }
34 |
35 | // WriteLevel implements LevelWriter interface.
36 | func (sw syslogWriter) WriteLevel(level Level, p []byte) (n int, err error) {
37 | switch level {
38 | case DebugLevel:
39 | err = sw.w.Debug(string(p))
40 | case InfoLevel:
41 | err = sw.w.Info(string(p))
42 | case WarnLevel:
43 | err = sw.w.Warning(string(p))
44 | case ErrorLevel:
45 | err = sw.w.Err(string(p))
46 | case FatalLevel:
47 | err = sw.w.Emerg(string(p))
48 | case PanicLevel:
49 | err = sw.w.Crit(string(p))
50 | case NoLevel:
51 | err = sw.w.Info(string(p))
52 | default:
53 | panic("invalid level")
54 | }
55 | n = len(p)
56 | return
57 | }
58 |
59 | func (sw syslogWriter) FormatCaller(i string) string {
60 | return defaultFormatCaller(i)
61 | }
62 |
63 | func (sw syslogWriter) FormatTimestamp() string {
64 | return defaultFormatTimestamp()
65 | }
66 |
67 | func (sw syslogWriter) FormatMessage(i string) string {
68 | return defaultFormatMessage(i)
69 | }
70 |
71 | func (sw syslogWriter) FormatLevel(i string) string {
72 | return defaultFormatLevel(i)
73 | }
74 |
--------------------------------------------------------------------------------
/golang_common/zerolog/syslog_json_test.go:
--------------------------------------------------------------------------------
1 | // +build !binary_log
2 | // +build !windows
3 | // +build json_log
4 |
5 | package zerolog
6 |
7 | import "testing"
8 | import "reflect"
9 |
10 | type syslogEvent struct {
11 | level string
12 | msg string
13 | }
14 | type syslogTestWriter struct {
15 | events []syslogEvent
16 | }
17 |
18 | func (w *syslogTestWriter) Write(p []byte) (int, error) {
19 | return 0, nil
20 | }
21 | func (w *syslogTestWriter) Debug(m string) error {
22 | w.events = append(w.events, syslogEvent{"Debug", m})
23 | return nil
24 | }
25 | func (w *syslogTestWriter) Info(m string) error {
26 | w.events = append(w.events, syslogEvent{"Info", m})
27 | return nil
28 | }
29 | func (w *syslogTestWriter) Warning(m string) error {
30 | w.events = append(w.events, syslogEvent{"Warning", m})
31 | return nil
32 | }
33 | func (w *syslogTestWriter) Err(m string) error {
34 | w.events = append(w.events, syslogEvent{"Err", m})
35 | return nil
36 | }
37 | func (w *syslogTestWriter) Emerg(m string) error {
38 | w.events = append(w.events, syslogEvent{"Emerg", m})
39 | return nil
40 | }
41 | func (w *syslogTestWriter) Crit(m string) error {
42 | w.events = append(w.events, syslogEvent{"Crit", m})
43 | return nil
44 | }
45 |
46 | func TestSyslogWriter(t *testing.T) {
47 | sw := &syslogTestWriter{}
48 | log := New(SyslogLevelWriter(sw))
49 | log.Debug().Msg("debug")
50 | log.Info().Msg("info")
51 | log.Warn().Msg("warn")
52 | log.Error().Msg("error")
53 | log.Log().Msg("nolevel")
54 | want := []syslogEvent{
55 | {"Debug", `{"level":"debug","message":"debug"}` + "\n"},
56 | {"Info", `{"level":"info","message":"info"}` + "\n"},
57 | {"Warning", `{"level":"warn","message":"warn"}` + "\n"},
58 | {"Err", `{"level":"error","message":"error"}` + "\n"},
59 | {"Info", `{"message":"nolevel"}` + "\n"},
60 | }
61 | if got := sw.events; !reflect.DeepEqual(got, want) {
62 | t.Errorf("Invalid syslog message routing: want %v, got %v", want, got)
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/golang_common/zerolog/syslog_test.go:
--------------------------------------------------------------------------------
1 | // +build !binary_log
2 | // +build !windows
3 |
4 | package zerolog
5 |
6 | import "testing"
7 | import "reflect"
8 |
9 | type syslogEvent struct {
10 | level string
11 | msg string
12 | }
13 | type syslogTestWriter struct {
14 | events []syslogEvent
15 | }
16 |
17 | func (w *syslogTestWriter) Write(p []byte) (int, error) {
18 | return 0, nil
19 | }
20 | func (w *syslogTestWriter) Debug(m string) error {
21 | w.events = append(w.events, syslogEvent{"Debug", m})
22 | return nil
23 | }
24 | func (w *syslogTestWriter) Info(m string) error {
25 | w.events = append(w.events, syslogEvent{"Info", m})
26 | return nil
27 | }
28 | func (w *syslogTestWriter) Warning(m string) error {
29 | w.events = append(w.events, syslogEvent{"Warning", m})
30 | return nil
31 | }
32 | func (w *syslogTestWriter) Err(m string) error {
33 | w.events = append(w.events, syslogEvent{"Err", m})
34 | return nil
35 | }
36 | func (w *syslogTestWriter) Emerg(m string) error {
37 | w.events = append(w.events, syslogEvent{"Emerg", m})
38 | return nil
39 | }
40 | func (w *syslogTestWriter) Crit(m string) error {
41 | w.events = append(w.events, syslogEvent{"Crit", m})
42 | return nil
43 | }
44 |
45 | func TestSyslogWriter(t *testing.T) {
46 | sw := &syslogTestWriter{}
47 | log := New(SyslogLevelWriter(sw))
48 | log.Debug().Msg("debug")
49 | log.Info().Msg("info")
50 | log.Warn().Msg("warn")
51 | log.Error().Msg("error")
52 | log.Log().Msg("nolevel")
53 | want := []syslogEvent{
54 | {"Debug", `[DEBUG]||debug` + "\n"},
55 | {"Info", `[INFO]||info` + "\n"},
56 | {"Warning", `[WARNING]||warn` + "\n"},
57 | {"Err", `[ERROR]||error` + "\n"},
58 | {"Info", `` + "\n"},
59 | }
60 | if got := sw.events; !reflect.DeepEqual(got, want) {
61 | t.Errorf("Invalid syslog message routing: want %v, got %v", want, got)
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/golang_common/zerolog/utils.go:
--------------------------------------------------------------------------------
1 | package zerolog
2 |
3 | import (
4 | "io/ioutil"
5 | "path/filepath"
6 | "strconv"
7 | "strings"
8 | "time"
9 | )
10 |
11 | // GetFilesByDir ...
12 | func getFilesByDir(dir string) ([]string, error) {
13 | var fileList []string
14 | fs, err := ioutil.ReadDir(dir)
15 | if err != nil {
16 | return nil, err
17 | }
18 | for _, f := range fs {
19 | if f.IsDir() {
20 | continue
21 | }
22 | path := filepath.Join(dir, f.Name())
23 | fileList = append(fileList, path)
24 | }
25 |
26 | return fileList, nil
27 | }
28 |
29 | func getExpiredFilesByDir(dir string, beginTime int64, filePrefix string) ([]string, error) {
30 | var fileList []string
31 | fs, err := ioutil.ReadDir(dir)
32 | if err != nil {
33 | return nil, err
34 | }
35 | for _, f := range fs {
36 | if f.IsDir() {
37 | continue
38 | }
39 | filename := f.Name()
40 | if !strings.HasPrefix(filename, filePrefix) {
41 | continue
42 | }
43 | idx := strings.LastIndex(filename, ".")
44 | ts := filename[idx+1:]
45 | if len(ts) == 10 {
46 | dateStr := ts[0:8]
47 | hourStr := ts[8:]
48 | date, err := time.Parse("20060102", dateStr)
49 | if err != nil {
50 | return []string{}, err
51 | }
52 | reviseDate := date.Local()
53 | offset, err := strconv.ParseInt(hourStr, 10, 64)
54 | if err != nil {
55 | return []string{}, err
56 | }
57 | timeUnix := reviseDate.Unix() - int64(reviseDate.Hour())*3600 + offset*3600
58 | if timeUnix <= beginTime {
59 | path := filepath.Join(dir, filename)
60 | fileList = append(fileList, path)
61 | }
62 | }
63 | }
64 |
65 | return fileList, nil
66 | }
67 |
--------------------------------------------------------------------------------
/golang_common/zerolog/writer_json_test.go:
--------------------------------------------------------------------------------
1 | // +build !binary_log
2 | // +build !windows
3 | // +build json_log
4 |
5 | package zerolog
6 |
7 | import (
8 | "reflect"
9 | "testing"
10 | )
11 |
12 | func TestMultiSyslogWriter(t *testing.T) {
13 | sw := &syslogTestWriter{}
14 | log := New(MultiLevelWriter(SyslogLevelWriter(sw)))
15 | log.Debug().Msg("debug")
16 | log.Info().Msg("info")
17 | log.Warn().Msg("warn")
18 | log.Error().Msg("error")
19 | log.Log().Msg("nolevel")
20 | want := []syslogEvent{
21 | {"Debug", `{"level":"debug","message":"debug"}` + "\n"},
22 | {"Info", `{"level":"info","message":"info"}` + "\n"},
23 | {"Warning", `{"level":"warn","message":"warn"}` + "\n"},
24 | {"Err", `{"level":"error","message":"error"}` + "\n"},
25 | {"Info", `{"message":"nolevel"}` + "\n"},
26 | }
27 | if got := sw.events; !reflect.DeepEqual(got, want) {
28 | t.Errorf("Invalid syslog message routing: want %v, got %v", want, got)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/golang_common/zerolog/writer_test.go:
--------------------------------------------------------------------------------
1 | // +build !binary_log
2 | // +build !windows
3 |
4 | package zerolog
5 |
6 | import (
7 | "reflect"
8 | "testing"
9 | )
10 |
11 | func TestMultiSyslogWriter(t *testing.T) {
12 | sw := &syslogTestWriter{}
13 | log := New(MultiLevelWriter(SyslogLevelWriter(sw)))
14 | log.Debug().Msg("debug")
15 | log.Info().Msg("info")
16 | log.Warn().Msg("warn")
17 | log.Error().Msg("error")
18 | log.Log().Msg("nolevel")
19 | want := []syslogEvent{
20 | {"Debug", `[DEBUG]||debug` + "\n"},
21 | {"Info", `[INFO]||info` + "\n"},
22 | {"Warning", `[WARNING]||warn` + "\n"},
23 | {"Err", `[ERROR]||error` + "\n"},
24 | {"Info", `` + "\n"},
25 | }
26 | if got := sw.events; !reflect.DeepEqual(got, want) {
27 | t.Errorf("Invalid syslog message routing: want %v, got %v", want, got)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/grpc_proxy_middleware/grpc_black_list.go:
--------------------------------------------------------------------------------
1 | package grpc_proxy_middleware
2 |
3 | import (
4 | "fmt"
5 | "github.com/didi/gatekeeper/model"
6 | "github.com/didi/gatekeeper/public"
7 | "github.com/pkg/errors"
8 | "google.golang.org/grpc"
9 | "google.golang.org/grpc/peer"
10 | "log"
11 | "strings"
12 | )
13 |
14 | func GrpcBlackListMiddleware(serviceDetail *model.ServiceDetail) func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
15 | return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
16 | whiteListStr := serviceDetail.PluginConf.GetPath("grpc_whiteblacklist", "ip_white_list").MustString()
17 | blackListStr := serviceDetail.PluginConf.GetPath("grpc_whiteblacklist", "ip_black_list").MustString()
18 |
19 | peerCtx, ok := peer.FromContext(ss.Context())
20 | if !ok {
21 | return errors.New("peer not found with context")
22 | }
23 | peerAddr := peerCtx.Addr.String()
24 | addrPos := strings.LastIndex(peerAddr, ":")
25 | clientIP := peerAddr[0:addrPos]
26 |
27 | if whiteListStr == "" && blackListStr != "" {
28 | if public.InIPSliceStr(clientIP, blackListStr) {
29 | return errors.New(fmt.Sprintf("%s in black ip list", clientIP))
30 | }
31 | }
32 | if err := handler(srv, ss); err != nil {
33 | log.Printf("RPC failed with error %v\n", err)
34 | return err
35 | }
36 | return nil
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/grpc_proxy_middleware/grpc_flow_count.go:
--------------------------------------------------------------------------------
1 | package grpc_proxy_middleware
2 |
3 | import (
4 | "github.com/didi/gatekeeper/model"
5 | "github.com/didi/gatekeeper/handler"
6 | "github.com/didi/gatekeeper/public"
7 | "google.golang.org/grpc"
8 | "log"
9 | )
10 |
11 | func GrpcFlowCountMiddleware(serviceDetail *model.ServiceDetail) func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error{
12 | return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, sHandler grpc.StreamHandler) error{
13 | totalCounter, err := handler.ServiceCounterHandler.GetCounter(public.FlowTotal)
14 | if err != nil {
15 | return err
16 | }
17 | totalCounter.Increase()
18 | serviceCounter, err := handler.ServiceCounterHandler.GetCounter(public.FlowServicePrefix + serviceDetail.Info.ServiceName)
19 | if err != nil {
20 | return err
21 | }
22 | serviceCounter.Increase()
23 |
24 | if err := sHandler(srv, ss);err != nil {
25 | log.Printf("GrpcFlowCountMiddleware failed with error %v\n", err)
26 | return err
27 | }
28 | return nil
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/grpc_proxy_middleware/grpc_jwt_auth_token.go:
--------------------------------------------------------------------------------
1 | package grpc_proxy_middleware
2 |
3 | import (
4 | "github.com/didi/gatekeeper/handler"
5 | "github.com/didi/gatekeeper/model"
6 | "github.com/didi/gatekeeper/public"
7 | "github.com/pkg/errors"
8 | "google.golang.org/grpc"
9 | "google.golang.org/grpc/metadata"
10 | "log"
11 | "strings"
12 | )
13 |
14 | //jwt auth token
15 | func GrpcJwtAuthTokenMiddleware(serviceDetail *model.ServiceDetail) func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
16 | return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, grpcHandler grpc.StreamHandler) error {
17 | md, ok := metadata.FromIncomingContext(ss.Context())
18 | if !ok {
19 | return errors.New("miss metadata from context")
20 | }
21 | if serviceDetail.Info.AuthType != "jwt_auth" {
22 | if err := grpcHandler(srv, ss); err != nil {
23 | log.Printf("GrpcJwtAuthTokenMiddleware failed with error %v\n", err)
24 | return err
25 | }
26 | return nil
27 | }
28 |
29 | authToken := ""
30 | auths := md.Get("authorization")
31 | if len(auths) > 0 {
32 | authToken = auths[0]
33 | }
34 | appMatched := false
35 | claims, err := public.JwtDecode(strings.ReplaceAll(authToken, "Bearer ", ""))
36 | if err != nil {
37 | return errors.WithMessage(err, "JwtDecode")
38 | }
39 | appList := handler.AppManagerHandler.GetAppList()
40 | for _, appInfo := range appList {
41 | if appInfo.AppID == claims.Issuer {
42 | md.Set("app", public.Obj2Json(appInfo))
43 | appMatched = true
44 | break
45 | }
46 | }
47 | if !appMatched {
48 | return errors.New("not match valid app")
49 | }
50 | if err := grpcHandler(srv, ss); err != nil {
51 | log.Printf("GrpcJwtAuthTokenMiddleware failed with error %v\n", err)
52 | return err
53 | }
54 | return nil
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/grpc_proxy_middleware/grpc_jwt_flow_count.go:
--------------------------------------------------------------------------------
1 | package grpc_proxy_middleware
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "github.com/didi/gatekeeper/handler"
7 | "github.com/didi/gatekeeper/model"
8 | "github.com/didi/gatekeeper/public"
9 | "github.com/pkg/errors"
10 | "google.golang.org/grpc"
11 | "google.golang.org/grpc/metadata"
12 | "log"
13 | )
14 |
15 | func GrpcJwtFlowCountMiddleware(serviceDetail *model.ServiceDetail) func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error{
16 | return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, grpcHandler grpc.StreamHandler) error{
17 | md, ok := metadata.FromIncomingContext(ss.Context())
18 | if !ok {
19 | return errors.New("miss metadata from context")
20 | }
21 | if serviceDetail.Info.AuthType != "jwt_auth" {
22 | if err := grpcHandler(srv, ss); err != nil {
23 | log.Printf("GrpcJwtAuthTokenMiddleware failed with error %v\n", err)
24 | return err
25 | }
26 | return nil
27 | }
28 |
29 | appInfos := md.Get("app")
30 | if len(appInfos)==0 {
31 | if err := grpcHandler(srv, ss);err != nil {
32 | log.Printf("RPC failed with error %v\n", err)
33 | return err
34 | }
35 | return nil
36 | }
37 | appInfo := &model.App{}
38 | if err:=json.Unmarshal([]byte(appInfos[0]),appInfo);err!=nil{
39 | return err
40 | }
41 | appCounter, err := handler.AppCounterHandler.GetCounter(public.FlowAppPrefix + appInfo.AppID)
42 | if err != nil {
43 | return err
44 | }
45 | appCounter.Increase()
46 | if appInfo.Qpd>0 && appCounter.TotalCount>appInfo.Qpd{
47 | return errors.New(fmt.Sprintf("租户日请求量限流 limit:%v current:%v",appInfo.Qpd,appCounter.TotalCount))
48 | }
49 | if err := grpcHandler(srv, ss);err != nil {
50 | log.Printf("RPC failed with error %v\n", err)
51 | return err
52 | }
53 | return nil
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/grpc_proxy_middleware/grpc_metadata_transfer.go:
--------------------------------------------------------------------------------
1 | package grpc_proxy_middleware
2 |
3 | import (
4 | "github.com/didi/gatekeeper/model"
5 | "github.com/pkg/errors"
6 | "google.golang.org/grpc"
7 | "google.golang.org/grpc/metadata"
8 | "log"
9 | "strings"
10 | )
11 |
12 | func GrpcMetadataTransferMiddleware(serviceDetail *model.ServiceDetail) func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
13 | return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
14 | md, ok := metadata.FromIncomingContext(ss.Context())
15 | if !ok {
16 | return errors.New("miss metadata from context")
17 | }
18 | transferRule := serviceDetail.PluginConf.GetPath("metadata_transfer","transfer_rule").MustString()
19 | for _, item := range strings.Split(transferRule, ",") {
20 | items := strings.Split(item, " ")
21 | if len(items) != 3 {
22 | continue
23 | }
24 | if items[0] == "add" || items[0] == "edit" {
25 | md.Set(items[1], items[2])
26 | }
27 | if items[0] == "del" {
28 | delete(md, items[1])
29 | }
30 | }
31 | if err := ss.SetHeader(md); err != nil {
32 | return errors.WithMessage(err, "SetHeader")
33 | }
34 | if err := handler(srv, ss); err != nil {
35 | log.Printf("RPC failed with error %v\n", err)
36 | return err
37 | }
38 | return nil
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/grpc_proxy_middleware/grpc_test.go:
--------------------------------------------------------------------------------
1 | package grpc_proxy_middleware
2 |
3 | import (
4 | "google.golang.org/grpc"
5 | "log"
6 | )
7 |
8 | //流式RPC拦截器
9 | func GrpcAuthStreamInterceptor(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
10 | err := handler(srv, ss)
11 | if err != nil {
12 | log.Printf("RPC failed with error %v\n", err)
13 | }
14 | return err
15 | }
16 |
--------------------------------------------------------------------------------
/grpc_proxy_middleware/grpc_white_list.go:
--------------------------------------------------------------------------------
1 | package grpc_proxy_middleware
2 |
3 | import (
4 | "fmt"
5 | "github.com/didi/gatekeeper/model"
6 | "github.com/didi/gatekeeper/public"
7 | "github.com/pkg/errors"
8 | "google.golang.org/grpc"
9 | "google.golang.org/grpc/peer"
10 | "log"
11 | "strings"
12 | )
13 |
14 | //匹配接入方式 基于请求信息
15 | func GrpcWhiteListMiddleware(serviceDetail *model.ServiceDetail) func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
16 | return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
17 | peerCtx, ok := peer.FromContext(ss.Context())
18 | if !ok {
19 | return errors.New("peer not found with context")
20 | }
21 | peerAddr := peerCtx.Addr.String()
22 | addrPos := strings.LastIndex(peerAddr, ":")
23 | clientIP := peerAddr[0:addrPos]
24 |
25 | whiteListStr := serviceDetail.PluginConf.GetPath("grpc_whiteblacklist", "ip_white_list").MustString()
26 | if whiteListStr != "" {
27 | if !public.InIPSliceStr(clientIP, whiteListStr) {
28 | return errors.New(fmt.Sprintf("%s not in white ip list", clientIP))
29 | }
30 | }
31 | if err := handler(srv, ss); err != nil {
32 | log.Printf("RPC failed with error %v\n", err)
33 | return err
34 | }
35 | return nil
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/handler/app_count_handler.go:
--------------------------------------------------------------------------------
1 | package handler
2 |
3 | import (
4 | "github.com/didi/gatekeeper/public"
5 | "log"
6 | "sync"
7 | )
8 |
9 | var AppCounterHandler *FlowAppCounter
10 |
11 | type FlowAppCounter struct {
12 | FlowCounter
13 | }
14 |
15 | func NewFlowAppCounter() *FlowAppCounter {
16 | return &FlowAppCounter{
17 | FlowCounter{
18 | RedisFlowCountMap: map[string]*DistributedCountService{},
19 | Locker: sync.RWMutex{},
20 | },
21 | }
22 | }
23 |
24 | func (counter *FlowAppCounter) Update(e *AppEvent) {
25 | log.Printf("FlowAppCounter.Update\n")
26 | for _, app := range e.AddApp {
27 | counter.GetCounter(public.FlowAppPrefix + app.AppID)
28 | }
29 | for _, item := range counter.RedisFlowCountMap {
30 | for _, app := range e.DeleteApp {
31 | if item.Name == public.FlowAppPrefix+app.AppID {
32 | item.Close()
33 | delete(counter.RedisFlowCountMap, item.Name)
34 | }
35 | }
36 | }
37 | }
38 |
39 | func init() {
40 | AppCounterHandler = NewFlowAppCounter()
41 | }
42 |
--------------------------------------------------------------------------------
/handler/service_count_handler.go:
--------------------------------------------------------------------------------
1 | package handler
2 |
3 | import (
4 | "github.com/didi/gatekeeper/public"
5 | "sync"
6 | "time"
7 | )
8 |
9 | var ServiceCounterHandler *FlowCounter
10 |
11 | type FlowCounter struct {
12 | RedisFlowCountMap map[string]*DistributedCountService
13 | Locker sync.RWMutex
14 | }
15 |
16 | func NewFlowCounter() *FlowCounter {
17 | return &FlowCounter{
18 | RedisFlowCountMap: map[string]*DistributedCountService{},
19 | Locker: sync.RWMutex{},
20 | }
21 | }
22 |
23 | func init() {
24 | ServiceCounterHandler = NewFlowCounter()
25 | ServiceManagerHandler.Regist(ServiceCounterHandler)
26 | }
27 |
28 | func (counter *FlowCounter) Update(e *ServiceEvent) {
29 | for _, service := range e.AddService {
30 | counter.GetCounter(public.FlowServicePrefix + service.Info.ServiceName)
31 | }
32 | for _, item := range counter.RedisFlowCountMap {
33 | for _, service := range e.DeleteService {
34 | if item.Name == public.FlowServicePrefix+service.Info.ServiceName {
35 | item.Close()
36 | delete(counter.RedisFlowCountMap, item.Name)
37 | }
38 | }
39 | }
40 | }
41 |
42 | func (counter *FlowCounter) GetCounter(name string) (*DistributedCountService, error) {
43 | counter.Locker.Lock()
44 | defer counter.Locker.Unlock()
45 | if item, ok := counter.RedisFlowCountMap[name]; ok {
46 | return item, nil
47 | }
48 | newCounter := NewDistributedCountService(name, 1*time.Second)
49 | counter.RedisFlowCountMap[name] = newCounter
50 | return newCounter, nil
51 | }
52 |
--------------------------------------------------------------------------------
/http_proxy_middleware/http_access_mode.go:
--------------------------------------------------------------------------------
1 | package http_proxy_middleware
2 |
3 | import (
4 | "github.com/didi/gatekeeper/handler"
5 | "github.com/didi/gatekeeper/public"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | //匹配接入方式 基于请求信息
10 | func HTTPAccessModeMiddleware() gin.HandlerFunc {
11 | return func(c *gin.Context) {
12 | service, err := handler.ServiceManagerHandler.HTTPAccessMode(c)
13 | if err != nil {
14 | public.ResponseError(c, 1001, err)
15 | c.Abort()
16 | return
17 | }
18 | c.Set(public.ServiceDetailContextKey, service)
19 | c.Next()
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/http_proxy_middleware/http_black_list.go:
--------------------------------------------------------------------------------
1 | package http_proxy_middleware
2 |
3 | import (
4 | "fmt"
5 | "github.com/didi/gatekeeper/model"
6 | "github.com/didi/gatekeeper/public"
7 | "github.com/gin-gonic/gin"
8 | "github.com/pkg/errors"
9 | )
10 |
11 | //匹配接入方式 基于请求信息
12 | func HTTPBlackListMiddleware() gin.HandlerFunc {
13 | return func(c *gin.Context) {
14 | serviceDetail, err := model.GetServiceDetailFromGinContext(c)
15 | if err != nil {
16 | public.ResponseError(c, 2001, err)
17 | c.Abort()
18 | return
19 | }
20 |
21 | whiteListStr := serviceDetail.PluginConf.GetPath("http_whiteblacklist", "ip_white_list").MustString()
22 | blackListStr := serviceDetail.PluginConf.GetPath("http_whiteblacklist", "ip_black_list").MustString()
23 | if whiteListStr == "" && public.InIPSliceStr(c.ClientIP(), blackListStr) {
24 | public.ResponseError(c, 3001, errors.New(fmt.Sprintf("%s in black ip list", c.ClientIP())))
25 | c.Abort()
26 | return
27 | }
28 |
29 | c.Next()
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/http_proxy_middleware/http_flow_count.go:
--------------------------------------------------------------------------------
1 | package http_proxy_middleware
2 |
3 | import (
4 | "bytes"
5 | "github.com/didi/gatekeeper/handler"
6 | "github.com/didi/gatekeeper/model"
7 | "github.com/didi/gatekeeper/public"
8 | "github.com/gin-gonic/gin"
9 | )
10 |
11 | func HTTPFlowCountMiddleware() gin.HandlerFunc {
12 | return func(c *gin.Context) {
13 | serviceDetail,err:= model.GetServiceDetailFromGinContext(c)
14 | if err!=nil{
15 | public.ResponseError(c, 2001, err)
16 | c.Abort()
17 | return
18 | }
19 | totalCounter, err := handler.ServiceCounterHandler.GetCounter(public.FlowTotal)
20 | if err != nil {
21 | public.ResponseError(c, 4001, err)
22 | c.Abort()
23 | return
24 | }
25 | totalCounter.Increase()
26 |
27 | sCounterBuffer := bytes.NewBufferString(public.FlowServicePrefix)
28 | sCounterBuffer.WriteString(serviceDetail.Info.ServiceName)
29 | serviceCounter, err := handler.ServiceCounterHandler.GetCounter(sCounterBuffer.String())
30 | if err != nil {
31 | public.ResponseError(c, 4001, err)
32 | c.Abort()
33 | return
34 | }
35 | serviceCounter.Increase()
36 | c.Next()
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/http_proxy_middleware/http_header_transfer.go:
--------------------------------------------------------------------------------
1 | package http_proxy_middleware
2 |
3 | import (
4 | "github.com/didi/gatekeeper/model"
5 | "github.com/didi/gatekeeper/public"
6 | "github.com/gin-gonic/gin"
7 | "strings"
8 | )
9 |
10 | func HTTPHeaderTransferMiddleware() gin.HandlerFunc {
11 | return func(c *gin.Context) {
12 | serviceDetail, err := model.GetServiceDetailFromGinContext(c)
13 | if err != nil {
14 | public.ResponseError(c, 2001, err)
15 | c.Abort()
16 | return
17 | }
18 | transferRule := serviceDetail.PluginConf.GetPath("header_transfer", "header_transfer_rule").MustString()
19 | for _, item := range strings.Split(transferRule, "\n") {
20 | if item == "" {
21 | continue
22 | }
23 | items := strings.Split(item, " ")
24 | if len(items) == 3 {
25 | if items[0] == "add" {
26 | c.Request.Header.Add(items[1], items[2])
27 | }
28 | if items[0] == "edit" {
29 | c.Request.Header.Set(items[1], items[2])
30 | }
31 | continue
32 | }
33 | if len(items) == 2 && items[0] == "del" {
34 | c.Request.Header.Del(items[1])
35 | }
36 | }
37 | c.Next()
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/http_proxy_middleware/http_jwt_auth_token.go:
--------------------------------------------------------------------------------
1 | package http_proxy_middleware
2 |
3 | import (
4 | "github.com/didi/gatekeeper/handler"
5 | "github.com/didi/gatekeeper/model"
6 | "github.com/didi/gatekeeper/public"
7 | "github.com/gin-gonic/gin"
8 | "github.com/pkg/errors"
9 | "strings"
10 | )
11 |
12 | func HTTPJwtAuthTokenMiddleware() gin.HandlerFunc {
13 | return func(c *gin.Context) {
14 | serviceDetail, err := model.GetServiceDetailFromGinContext(c)
15 | if err != nil {
16 | public.ResponseError(c, 2001, err)
17 | c.Abort()
18 | return
19 | }
20 | if serviceDetail.Info.AuthType != "jwt_auth" {
21 | c.Next()
22 | return
23 | }
24 | appMatched := false
25 | claims, err := public.JwtDecode(strings.ReplaceAll(c.GetHeader("Authorization"), "Bearer ", ""))
26 | if err != nil {
27 | public.ResponseError(c, 2002, err)
28 | c.Abort()
29 | return
30 | }
31 | appList := handler.AppManagerHandler.GetAppList()
32 | for _, appInfo := range appList {
33 | if appInfo.AppID == claims.Issuer {
34 | c.Set("app", appInfo)
35 | appMatched = true
36 | break
37 | }
38 | }
39 | if !appMatched {
40 | public.ResponseError(c, 2003, errors.New("not match valid app"))
41 | c.Abort()
42 | return
43 | }
44 | c.Next()
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/http_proxy_middleware/http_jwt_flow_count.go:
--------------------------------------------------------------------------------
1 | package http_proxy_middleware
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "github.com/didi/gatekeeper/handler"
7 | "github.com/didi/gatekeeper/model"
8 | "github.com/didi/gatekeeper/public"
9 | "github.com/gin-gonic/gin"
10 | "errors"
11 | )
12 |
13 | func HTTPJwtFlowCountMiddleware() gin.HandlerFunc {
14 | return func(c *gin.Context) {
15 | serviceDetail, err := model.GetServiceDetailFromGinContext(c)
16 | if err != nil {
17 | public.ResponseError(c, 2001, err)
18 | c.Abort()
19 | return
20 | }
21 | if serviceDetail.Info.AuthType != "jwt_auth" {
22 | c.Next()
23 | return
24 | }
25 |
26 | appInterface, ok := c.Get("app")
27 | if !ok {
28 | c.Next()
29 | return
30 | }
31 | appInfo := appInterface.(*model.App)
32 | countBuffer := bytes.NewBufferString(public.FlowAppPrefix)
33 | countBuffer.WriteString(appInfo.AppID)
34 | appCounter, err := handler.ServiceCounterHandler.GetCounter(countBuffer.String())
35 | if err != nil {
36 | public.ResponseError(c, 2002, err)
37 | c.Abort()
38 | return
39 | }
40 | appCounter.Increase()
41 | if appInfo.Qpd > 0 && appCounter.TotalCount > appInfo.Qpd {
42 | public.ResponseError(c, 2003, errors.New(fmt.Sprintf("租户日请求量限流 limit:%v current:%v", appInfo.Qpd, appCounter.TotalCount)))
43 | c.Abort()
44 | return
45 | }
46 | c.Next()
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/http_proxy_middleware/http_jwt_flow_limit.go:
--------------------------------------------------------------------------------
1 | package http_proxy_middleware
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "github.com/didi/gatekeeper/handler"
7 | "github.com/didi/gatekeeper/model"
8 | "github.com/didi/gatekeeper/public"
9 | "github.com/gin-gonic/gin"
10 | "errors"
11 | )
12 |
13 | func HTTPJwtFlowLimitMiddleware() gin.HandlerFunc {
14 | return func(c *gin.Context) {
15 | serviceDetail, err := model.GetServiceDetailFromGinContext(c)
16 | if err != nil {
17 | public.ResponseError(c, 2001, err)
18 | c.Abort()
19 | return
20 | }
21 | if serviceDetail.Info.AuthType != "jwt_auth" {
22 | c.Next()
23 | return
24 | }
25 |
26 | appInterface, ok := c.Get("app")
27 | if !ok {
28 | c.Next()
29 | return
30 | }
31 | appInfo := appInterface.(*model.App)
32 | if appInfo.Qps > 0 {
33 | cLimiterBuffer := bytes.NewBufferString(public.FlowAppPrefix)
34 | cLimiterBuffer.WriteString(appInfo.AppID)
35 | cLimiterBuffer.WriteString("_")
36 | //cLimiterBuffer.WriteString(c.ClientIP())
37 | clientLimiter, err := handler.FlowLimiterHandler.GetLimiter(cLimiterBuffer.String(), float64(appInfo.Qps), 0, true)
38 | if err != nil {
39 | public.ResponseError(c, 5001, err)
40 | c.Abort()
41 | return
42 | }
43 | if !clientLimiter.Allow() {
44 | public.ResponseError(c, 5002, errors.New(fmt.Sprintf("%v flow limit %v", c.ClientIP(), appInfo.Qps), ))
45 | c.Abort()
46 | return
47 | }
48 | }
49 | c.Next()
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/http_proxy_middleware/http_recovery.go:
--------------------------------------------------------------------------------
1 | package http_proxy_middleware
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "github.com/didi/gatekeeper/golang_common/lib"
7 | "github.com/didi/gatekeeper/golang_common/trace"
8 | "github.com/didi/gatekeeper/public"
9 | "github.com/gin-gonic/gin"
10 | "runtime/debug"
11 | )
12 |
13 | func HTTPRecoveryMiddleware() gin.HandlerFunc {
14 | return func(c *gin.Context) {
15 | defer func() {
16 | if err := recover(); err != nil {
17 | if lib.ConfBase.Log.On {
18 | public.GinLogWarning(c, trace.DLTagUndefined, map[string]interface{}{
19 | "error": fmt.Sprint(err),
20 | "stack": string(debug.Stack()),
21 | })
22 | }
23 | public.ResponseError(c, 500, errors.New(fmt.Sprint(err)+"||"+string(debug.Stack())))
24 | return
25 | }
26 | }()
27 | c.Next()
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/http_proxy_middleware/http_request_log.go:
--------------------------------------------------------------------------------
1 | package http_proxy_middleware
2 |
3 | import (
4 | "github.com/didi/gatekeeper/golang_common/lib"
5 | "github.com/didi/gatekeeper/golang_common/trace"
6 | "github.com/gin-gonic/gin"
7 | "time"
8 | )
9 |
10 | func HTTPRequestLogger() gin.HandlerFunc {
11 | return func(c *gin.Context) {
12 | if !lib.ConfBase.Log.On {
13 | c.Next()
14 | return
15 | }
16 | t := time.Now()
17 | c.Request = c.Request.WithContext(trace.SetCtxTrace(c.Request.Context(), trace.New(c.Request)))
18 | lib.ZLog.Infof(c.Request.Context(), trace.DLTagRequestIn, "")
19 | c.Next()
20 | lib.ZLog.Infof(c.Request.Context(), trace.DLTagRequestOut, "proc_time=%f||status=%v", time.Since(t).Seconds(), c.Writer.Status())
21 | if traceCtx, ok := trace.GetCtxTrace(c.Request.Context()); ok {
22 | trace.PutTrace(traceCtx)
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/http_proxy_middleware/http_reverse_proxy.go:
--------------------------------------------------------------------------------
1 | package http_proxy_middleware
2 |
3 | import (
4 | "github.com/didi/gatekeeper/handler"
5 | "github.com/didi/gatekeeper/model"
6 | "github.com/didi/gatekeeper/public"
7 | "github.com/didi/gatekeeper/reverse_proxy"
8 | "github.com/gin-gonic/gin"
9 | )
10 |
11 | func HTTPReverseProxyMiddleware() gin.HandlerFunc {
12 | return func(c *gin.Context) {
13 | serviceDetail, err := model.GetServiceDetailFromGinContext(c)
14 | if err != nil {
15 | public.ResponseError(c, 2001, err)
16 | c.Abort()
17 | return
18 | }
19 | lb, err := handler.LoadBalancerHandler.GetLoadBalancer(serviceDetail)
20 | if err != nil {
21 | public.ResponseError(c, 2002, err)
22 | c.Abort()
23 | return
24 | }
25 | trans, err := handler.TransportorHandler.GetTrans(serviceDetail)
26 | if err != nil {
27 | public.ResponseError(c, 2003, err)
28 | c.Abort()
29 | return
30 | }
31 | proxy := reverse_proxy.NewLoadBalanceReverseProxy(c, lb, trans)
32 | proxy.ServeHTTP(c.Writer, c.Request)
33 | c.Abort()
34 | return
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/http_proxy_middleware/http_strip_uri.go:
--------------------------------------------------------------------------------
1 | package http_proxy_middleware
2 |
3 | import (
4 | "strings"
5 |
6 | "github.com/didi/gatekeeper/model"
7 | "github.com/didi/gatekeeper/public"
8 | "github.com/gin-gonic/gin"
9 | )
10 |
11 | func HTTPStripUriMiddleware() gin.HandlerFunc {
12 | return func(c *gin.Context) {
13 | serviceDetail, err := model.GetServiceDetailFromGinContext(c)
14 | if err != nil {
15 | public.ResponseError(c, 2001, err)
16 | c.Abort()
17 | return
18 | }
19 | if serviceDetail.Info.HttpStripPrefix == 1 {
20 | strArr := strings.Split(serviceDetail.Info.HTTPPaths,"\n")
21 | tmpStr := c.Request.URL.Path
22 | for _, replaceStr := range strArr {
23 | c.Request.URL.Path = strings.Replace(c.Request.URL.Path, replaceStr, "", 1)
24 | if c.Request.URL.Path != tmpStr {
25 | break
26 | }
27 | }
28 |
29 | }
30 | c.Next()
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/http_proxy_middleware/http_url_rewrite.go:
--------------------------------------------------------------------------------
1 | package http_proxy_middleware
2 |
3 | import (
4 | "github.com/didi/gatekeeper/model"
5 | "github.com/didi/gatekeeper/public"
6 | "github.com/gin-gonic/gin"
7 | "regexp"
8 | "strings"
9 | )
10 |
11 | func HTTPUrlRewriteMiddleware() gin.HandlerFunc {
12 | return func(c *gin.Context) {
13 | serviceDetail, err := model.GetServiceDetailFromGinContext(c)
14 | if err != nil {
15 | public.ResponseError(c, 2001, err)
16 | c.Abort()
17 | return
18 | }
19 | rewriteUrl := serviceDetail.PluginConf.GetPath("url_rewrite", "rewrite_rule").MustString()
20 | if rewriteUrl == "" {
21 | c.Next()
22 | return
23 | }
24 | for _, item := range strings.Split(rewriteUrl, ",") {
25 | items := strings.Split(item, " ")
26 | if len(items) != 2 {
27 | continue
28 | }
29 | regexp, err := regexp.Compile(items[0])
30 | if err != nil {
31 | continue
32 | }
33 | replacePath := regexp.ReplaceAll([]byte(c.Request.URL.Path), []byte(items[1]))
34 | c.Request.URL.Path = string(replacePath)
35 | }
36 | c.Next()
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/http_proxy_middleware/http_white_list.go:
--------------------------------------------------------------------------------
1 | package http_proxy_middleware
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "github.com/didi/gatekeeper/model"
7 | "github.com/didi/gatekeeper/public"
8 | "github.com/gin-gonic/gin"
9 | )
10 |
11 | func HTTPWhiteListMiddleware() gin.HandlerFunc {
12 | return func(c *gin.Context) {
13 | serviceDetail, err := model.GetServiceDetailFromGinContext(c)
14 | if err != nil {
15 | public.ResponseError(c, 2001, err)
16 | c.Abort()
17 | return
18 | }
19 |
20 | ipWhiteListString := serviceDetail.PluginConf.GetPath("http_whiteblacklist", "ip_white_list").MustString()
21 | if ipWhiteListString != "" {
22 | if !public.InIPSliceStr(c.ClientIP(), ipWhiteListString) {
23 | public.ResponseError(c, 3001, errors.New(fmt.Sprintf("%s not in white ip list", c.ClientIP())))
24 | c.Abort()
25 | return
26 | }
27 | }
28 |
29 |
30 | urlWhiteUrlString := serviceDetail.PluginConf.GetPath("http_whiteblacklist", "url_white_list").MustString()
31 | if urlWhiteUrlString != "" {
32 | if !public.InURLSliceStr(c.Request.URL.Path, urlWhiteUrlString) {
33 | public.ResponseError(c, 3001, errors.New(fmt.Sprintf("%s not in white url list", c.Request.URL.Path)))
34 | c.Abort()
35 | return
36 | }
37 | }
38 |
39 | c.Set("ip_white_list", ipWhiteListString)
40 | c.Set("url_white_list", urlWhiteUrlString)
41 | c.Next()
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/http_proxy_router/route.go:
--------------------------------------------------------------------------------
1 | package http_proxy_router
2 |
3 | import (
4 | "github.com/didi/gatekeeper/dashboard_controller"
5 | "github.com/didi/gatekeeper/http_proxy_middleware"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | func InitRouter(middlewares ...gin.HandlerFunc) *gin.Engine {
10 | router := gin.New()
11 | router.Use(middlewares...)
12 | router.GET("/ping", func(c *gin.Context) {
13 | c.JSON(200, gin.H{
14 | "message": "pong",
15 | })
16 | })
17 | oauth := router.Group("/oauth")
18 | oauth.Use(http_proxy_middleware.TranslationMiddleware())
19 | {
20 | dashboard_controller.OAuthRegister(oauth)
21 | }
22 | router.Use(
23 | http_proxy_middleware.HTTPAccessModeMiddleware(),
24 | http_proxy_middleware.HTTPFlowCountMiddleware(),
25 | http_proxy_middleware.HTTPFlowLimitMiddleware(),
26 | http_proxy_middleware.HTTPWhiteListMiddleware(),
27 | http_proxy_middleware.HTTPBlackListMiddleware(),
28 | http_proxy_middleware.HTTPJwtAuthTokenMiddleware(),
29 | http_proxy_middleware.HTTPJwtFlowCountMiddleware(),
30 | http_proxy_middleware.HTTPJwtFlowLimitMiddleware(),
31 | http_proxy_middleware.HTTPHeaderTransferMiddleware(),
32 | http_proxy_middleware.HTTPStripUriMiddleware(),
33 | http_proxy_middleware.HTTPUrlRewriteMiddleware(),
34 | http_proxy_middleware.HTTPReverseProxyMiddleware())
35 | return router
36 | }
37 |
--------------------------------------------------------------------------------
/install/build.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | color 0d
3 |
4 | echo =================================
5 | echo ==========Build Linux ======
6 | echo =================================
7 | SET CGO_ENABLED=0
8 | SET GOOS=linux
9 | SET GOARCH=amd64
10 | echo now the CGO_ENABLED:
11 | go env CGO_ENABLED
12 | echo now the GOOS:
13 | go env GOOS
14 | echo now the GOARCH:
15 | go env GOARCH
16 | go build -o bin/install_linux main.go
17 |
18 | echo =================================
19 | echo ==========Build Mac ======
20 | echo =================================
21 | SET CGO_ENABLED=0
22 | SET GOOS=darwin
23 | SET GOARCH=amd64
24 | echo now the CGO_ENABLED:
25 | go env CGO_ENABLED
26 | echo now the GOOS:
27 | go env GOOS
28 | echo now the GOARCH:
29 | go env GOARCH
30 | go build -o bin/install_mac main.go
31 |
32 | echo =================================
33 | echo ==========Build Windows ======
34 | echo =================================
35 | SET CGO_ENABLED=1
36 | SET GOOS=windows
37 | SET GOARCH=amd64
38 | echo now the CGO_ENABLED:
39 | go env CGO_ENABLED
40 | echo now the GOOS:
41 | go env GOOS
42 | echo now the GOARCH:
43 | go env GOARCH
44 | go build -o bin/install_windows.exe main.go
45 |
46 |
47 |
--------------------------------------------------------------------------------
/install/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | function buildLinux() {
4 | echo =================================
5 | echo ==========Build Linux ======
6 | echo =================================
7 | CGO_ENABLED=0
8 | GOOS=linux
9 | GOARCH=amd64
10 | echo now the CGO_ENABLED:
11 | go env CGO_ENABLED
12 | echo now the GOOS:
13 | go env GOOS
14 | echo now the GOARCH:
15 | go env GOARCH
16 | go build -o bin/install_linux main.go
17 | }
18 |
19 |
20 | function buildMac() {
21 | echo =================================
22 | echo ==========Build Mac ======
23 | echo =================================
24 | CGO_ENABLED=0
25 | GOOS=darwin
26 | GOARCH=amd64
27 | echo now the CGO_ENABLED:
28 | go env CGO_ENABLED
29 | echo now the GOOS:
30 | go env GOOS
31 | echo now the GOARCH:
32 | go env GOARCH
33 | go build -o bin/install_mac main.go
34 | }
35 |
36 | function buildWindows() {
37 | echo =================================
38 | echo ==========Build Windows ======
39 | echo =================================
40 | CGO_ENABLED=1
41 | GOOS=windows
42 | GOARCH=amd64
43 | echo now the CGO_ENABLED:
44 | go env CGO_ENABLED
45 | echo now the GOOS:
46 | go env GOOS
47 | echo now the GOARCH:
48 | go env GOARCH
49 | go build -o bin/install_windows.exe main.go
50 | }
51 |
52 |
53 |
54 | buildLinux
55 | buildMac
56 | buildWindows
57 |
--------------------------------------------------------------------------------
/install/check/conf.go:
--------------------------------------------------------------------------------
1 | package check
2 |
3 | import (
4 | "fmt"
5 | "gatekeeper/install/template"
6 | "gatekeeper/install/tool"
7 | "io/ioutil"
8 | "strings"
9 | )
10 |
11 | var (
12 | ConfPath = GateKeeperPath + "/conf/dev/"
13 | )
14 |
15 | func InitConf() error {
16 |
17 | tool.LogInfo.Println("init conf start")
18 |
19 | err := initBase()
20 | if err != nil {
21 | return err
22 | }
23 |
24 |
25 | err = initRedis()
26 | if err != nil {
27 | return err
28 | }
29 |
30 | err = initMysql()
31 | if err != nil {
32 | return err
33 | }
34 | tool.LogInfo.Println("init conf end")
35 | return nil
36 | }
37 |
38 |
39 | func initBase() error {
40 | tool.LogInfo.Println("init base conf")
41 |
42 | fileName := ConfPath + "base.toml"
43 | redisClient := RedisClient.Host + ":" + RedisClient.Port
44 | baseConf := strings.Replace(template.BaseConf, "#REDIS_CLIENT", redisClient, 1)
45 | baseConf = strings.Replace(baseConf, "#REDIS_PWD", RedisClient.Pwd, 1)
46 | err := ioutil.WriteFile(fileName, []byte(baseConf), 0666); if err != nil{
47 | return err
48 | }
49 | return nil
50 |
51 | }
52 |
53 |
54 | func initRedis() error {
55 | tool.LogInfo.Println("init redis conf")
56 |
57 | fileName := ConfPath + "redis_map.toml"
58 | redisClient := RedisClient.Host + ":" + RedisClient.Port
59 | redisConf := strings.Replace(template.RedisConf, "#REDIS_CLIENT", redisClient, 1)
60 | redisConf = strings.Replace(redisConf, "#REDIS_PWD", RedisClient.Pwd, 1)
61 | err := ioutil.WriteFile(fileName, []byte(redisConf), 0666); if err != nil{
62 | return err
63 | }
64 | return nil
65 |
66 | }
67 |
68 |
69 | func initMysql() error {
70 | tool.LogInfo.Println("init mysql conf")
71 |
72 | fileName := ConfPath + "mysql_map.toml"
73 | mysqlClient := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true&loc=Local",
74 | MysqlClient.User,
75 | MysqlClient.Pwd,
76 | MysqlClient.Host,
77 | MysqlClient.Port,
78 | MysqlClient.Database)
79 | mysqlConf := strings.Replace(template.MysqlConf, "#MYSQL_CLIENT", mysqlClient, 1)
80 | err := ioutil.WriteFile(fileName, []byte(mysqlConf), 0666); if err != nil{
81 | return err
82 | }
83 | return nil
84 | }
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/install/check/gateway.go:
--------------------------------------------------------------------------------
1 | package check
2 |
3 | import (
4 | "fmt"
5 | "gatekeeper/install/tool"
6 | )
7 |
8 |
9 | var (
10 | GateKeeperPath string = tool.GateKeeperPath
11 | CmdRun string = "cd %s && %s run main.go run -c %s/conf/dev/ -p control"
12 | )
13 |
14 |
15 | func RunGateKeeper() error{
16 | boolRunGatekeeper, err := tool.Confirm("run gatekeeper?", 2)
17 | if err != nil{
18 | return err
19 | }
20 | CmdRun := fmt.Sprintf(tool.CmdRun + "&&" + CmdRun, GateKeeperPath, GoPath, GateKeeperPath)
21 | if boolRunGatekeeper {
22 | tool.LogInfo.Println(CmdRun)
23 | err := tool.RunCmd(CmdRun)
24 | if err != nil{
25 | return err
26 | }
27 | }
28 | return nil
29 | }
--------------------------------------------------------------------------------
/install/check/path.go:
--------------------------------------------------------------------------------
1 | package check
2 |
3 | import (
4 | "errors"
5 | "gatekeeper/install/tool"
6 | "regexp"
7 | "strconv"
8 | "strings"
9 | )
10 |
11 | var (
12 | UseVersion = "1.12.0"
13 | GoPath string = "go"
14 | )
15 |
16 | func InitGo() error{
17 | err := checkVersion()
18 | if err != nil{
19 | tool.LogWarning.Println(err)
20 | err = enterGoPath()
21 | if err != nil{
22 | return err
23 | }
24 |
25 | err = checkVersion()
26 | if err != nil{
27 | return err
28 | }
29 | }
30 |
31 | return nil
32 | }
33 |
34 |
35 | func checkVersion() error{
36 |
37 | str, err := tool.Cmd(GoPath + " version")
38 | if err != nil{
39 | return errors.New("go command not found")
40 | }
41 | versionPre := regexp.MustCompile(`[0-9]\.[0-9]{1,2}\.[0-9]*`)
42 | match := versionPre.FindString(string(str))
43 | goVersion, _ := strconv.Atoi(strings.Replace(match, ".", "", -1))
44 | useVersion, _ := strconv.Atoi(strings.Replace(UseVersion, ".", "", -1))
45 | if goVersion < useVersion {
46 | return errors.New("gatekeeper use go version must be >= 1.12.0 please check")
47 | }
48 | return nil
49 | }
50 |
51 |
52 | func enterGoPath() error{
53 | goPath, err := tool.Input("please enter go path (/use/bin/go):", "")
54 | if err != nil{
55 | return err
56 | }
57 | if goPath == ""{
58 | return errors.New("no go use")
59 | }
60 | GoPath = goPath
61 | return nil
62 | }
--------------------------------------------------------------------------------
/install/check/redis.go:
--------------------------------------------------------------------------------
1 | package check
2 |
3 | import (
4 | "fmt"
5 | "gatekeeper/install/tool"
6 | "github.com/go-redis/redis"
7 | )
8 |
9 |
10 | type Redis struct{
11 | Host string
12 | Port string
13 | Pwd string
14 | }
15 |
16 |
17 | var (
18 | RedisClient Redis
19 | )
20 |
21 |
22 | func InitRedis() error{
23 | host, err := tool.Input("please enter redis host (default:127.0.0.1)", "127.0.0.1")
24 | if err != nil{
25 | return err
26 | }
27 |
28 | port, err := tool.Input("please enter redis port (default:6379)", "6379")
29 | if err != nil{
30 | return err
31 | }
32 |
33 | pwd, err := tool.Input("please enter redis pwd (default:null)", "")
34 | if err != nil{
35 | return err
36 | }
37 |
38 | redisClient := Redis{
39 | Host: host,
40 | Port: port,
41 | Pwd: pwd,
42 | }
43 | RedisClient = redisClient
44 | tool.LogInfo.Println(fmt.Sprintf("redis connect info host:[%s] port:[%s] pwd:[%s]", host, port, pwd))
45 | err = redisClient.Init();if err !=nil{
46 | tool.LogError.Println(err)
47 | return err
48 | }
49 | return nil
50 | }
51 |
52 | func (r *Redis) Init() error{
53 | client := redis.NewClient(&redis.Options{
54 | Addr: fmt.Sprintf("%s:%s", r.Host, r.Port),
55 | Password: r.Pwd,
56 | DB: 0,
57 | })
58 | _, err := client.Ping().Result()
59 | if err != nil {
60 | tool.LogWarning.Println(err)
61 | return InitRedis()
62 | }
63 | tool.LogInfo.Println("connect redis success")
64 | return nil
65 | }
--------------------------------------------------------------------------------
/install/go.mod:
--------------------------------------------------------------------------------
1 | module gatekeeper/install
2 |
3 | go 1.15
4 |
5 | require (
6 | github.com/go-redis/redis v6.15.9+incompatible
7 | github.com/go-sql-driver/mysql v1.6.0
8 | github.com/pkg/errors v0.8.0
9 | )
10 |
--------------------------------------------------------------------------------
/install/go.sum:
--------------------------------------------------------------------------------
1 | github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
2 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
3 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
4 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
5 | github.com/didi/gatekeeper v0.1.1 h1:v3pahFkgiGQgnBk9Qz5/vxfskiP38m2z9D2VEnmZt5Q=
6 | github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
7 | github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
8 | github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
9 | github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
10 | github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
11 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
12 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
13 | github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
14 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
15 | github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
16 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
17 | github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
18 | github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
19 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
20 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
21 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
22 |
--------------------------------------------------------------------------------
/install/install.sh:
--------------------------------------------------------------------------------
1 | #! bin/bash
2 |
3 |
4 | # check go version
5 |
6 | function checkGoVerion() {
7 | useGoVersion="1120"
8 | goVersion=`go version |grep -Eo '([0-9])\.([0-9]{1,2})\.([0-9]*)' |awk -F '.' '{print $1 $2 $3}'`
9 | if [ ! -n "$goVersion" ] || [ "$goVersion" -le "$useGoVersion" ];then
10 | echo "go version < 1.12.0 pleace upgreate"
11 | echo "Installation package download address : https://golang.org/dl/ or https://golang.google.cn/dl/"
12 | echo "Installation tutorial address : https://www.runoob.com/go/go-environment.html"
13 | exit -1
14 | else
15 | initInstall
16 | fi
17 | }
18 |
19 |
20 | function initInstall() {
21 | export GO111MODULE=on && export GOPROXY=https://goproxy.cn
22 | go run main.go
23 | }
24 |
25 |
26 | checkGoVerion
27 |
--------------------------------------------------------------------------------
/install/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "gatekeeper/install/check"
5 | "gatekeeper/install/tool"
6 | "os"
7 | )
8 |
9 | func main() {
10 | var (
11 | err error
12 | )
13 |
14 | tool.InitSystem()
15 |
16 | err = check.InitRedis(); if err != nil{
17 | tool.LogError.Println("connect redis error")
18 | tool.LogError.Println(err)
19 | os.Exit(-1)
20 | }
21 |
22 | err = check.InitDb(); if err != nil{
23 | tool.LogError.Println(err)
24 | os.Exit(-1)
25 | }
26 |
27 | err = check.InitConf(); if err != nil{
28 | tool.LogError.Println(err)
29 | os.Exit(-1)
30 | }
31 |
32 | //err = check.InitGo(); if err != nil{
33 | // tool.LogWarning.Println(err)
34 | // os.Exit(-1)
35 | //}
36 | //
37 | //err = check.RunGateKeeper(); if err != nil{
38 | // tool.LogError.Println(err)
39 | // os.Exit(-1)
40 | //}
41 |
42 | }
43 |
44 |
--------------------------------------------------------------------------------
/install/template/mysql.go:
--------------------------------------------------------------------------------
1 | package template
2 |
3 | import (
4 | "bufio"
5 | "gatekeeper/install/tool"
6 | "os"
7 | "regexp"
8 | "strings"
9 | )
10 |
11 | var(
12 | TableSql map[string]string
13 | Tables map[string][]string
14 | )
15 |
16 | func InitSql() error {
17 | TableSql = make(map[string]string)
18 | Tables = make(map[string][]string)
19 | err := getCreateSql()
20 | if err != nil{
21 | return err
22 | }
23 | for tableName, sql := range TableSql {
24 | Tables[tableName] = strings.Split(sql, ";")
25 | }
26 | return nil
27 | }
28 |
29 |
30 | func getCreateSql() error{
31 | sqlFilePath := tool.GateKeeperPath + "/gatekeeper.sql"
32 | tool.LogInfo.Println("sql file path :" + sqlFilePath)
33 | tableName := ""
34 | tablePre := regexp.MustCompile(`gateway_[a-z_]*`)
35 | f, err := os.Open(sqlFilePath)
36 | if err != nil{
37 | return err
38 | }
39 | defer f.Close()
40 | r := bufio.NewReader(f)
41 | for {
42 | lineSql, err := tool.ReadLine(r)
43 | if strings.Index(lineSql, "/*") < 0 && strings.Index(lineSql, "--") < 0 && lineSql != "" {
44 | if strings.Index(lineSql, "DROP TABLE IF EXISTS") >= 0 {
45 | tableName = tablePre.FindString(lineSql)
46 | }
47 | TableSql[tableName] += lineSql
48 | }
49 | if err != nil {
50 | break
51 | }
52 | }
53 | return nil
54 | }
--------------------------------------------------------------------------------
/install/tool/log.go:
--------------------------------------------------------------------------------
1 | package tool
2 |
3 | import (
4 | "log"
5 | "os"
6 | )
7 |
8 | var (
9 | LogInfo *log.Logger
10 | LogError *log.Logger
11 | LogWarning *log.Logger
12 | )
13 |
14 | func init() {
15 | LogInfo = log.New(os.Stdout, "[INFO] ", log.Ldate|log.Ltime)
16 | LogError = log.New(os.Stderr, "[ERROR] ", log.Ldate|log.Ltime)
17 | LogWarning = log.New(os.Stderr, "[WARNING] ", log.Ldate|log.Ltime)
18 | }
19 |
--------------------------------------------------------------------------------
/install/tool/reader.go:
--------------------------------------------------------------------------------
1 | package tool
2 |
3 | import (
4 | "bufio"
5 | "fmt"
6 | "github.com/pkg/errors"
7 | "os"
8 | "strings"
9 | )
10 |
11 |
12 | func NewReader() *bufio.Reader {
13 | reader := bufio.NewReader(os.Stdin)
14 | return reader
15 | }
16 |
17 |
18 | func ReadStdin(reader *bufio.Reader, describe string)(string, error) {
19 | fmt.Print(describe)
20 | readString, err := reader.ReadString('\n')
21 | if err != nil {
22 | return "", err
23 | }
24 | readString = strings.Replace(readString, "\n", "", 1)
25 | return readString, nil
26 | }
27 |
28 |
29 | func Input(describe string, defaultString string) (string, error) {
30 | reader := NewReader()
31 | readStdin, err := ReadStdin(reader, describe)
32 | if err != nil {
33 | LogError.Println(err)
34 | LogError.Println("read input error")
35 | return "", err
36 | }
37 | readStdin = strings.Trim(readStdin, "\r")
38 | if readStdin == "" {
39 | readStdin = defaultString
40 | }
41 | fmt.Println(readStdin)
42 | return readStdin, nil
43 | }
44 |
45 |
46 | func Confirm(describe string, retry int) (bool, error) {
47 | describe += " please enter (y/n):"
48 |
49 | i := 1
50 | for i <= retry {
51 | isConfirm, err := confirm(describe)
52 | if err != nil{
53 | LogError.Println(err)
54 | LogError.Println("read input error")
55 | i++
56 | continue
57 | }
58 | return isConfirm, nil
59 | }
60 | return false, nil
61 | }
62 |
63 |
64 | func confirm(describe string) (bool, error){
65 | reader := NewReader()
66 | isConfirm, err := ReadStdin(reader, describe)
67 | if err != nil{
68 | return false, err
69 | }
70 | isConfirm = strings.ToLower(strings.Trim(isConfirm, "\r"))
71 | if isConfirm == "n" || isConfirm == "no"{
72 | return false, nil
73 | }
74 | if isConfirm == "y" || isConfirm == "yes"{
75 | return true, nil
76 | }
77 | return false, errors.New("please enter (y/n)")
78 | }
79 |
80 | func ReadLine(r *bufio.Reader) (string, error) {
81 | line, isprefix, err := r.ReadLine()
82 | for isprefix && err == nil {
83 | var bs []byte
84 | bs, isprefix, err = r.ReadLine()
85 | line = append(line, bs...)
86 | }
87 | return string(line), err
88 | }
--------------------------------------------------------------------------------
/install/tool/system.go:
--------------------------------------------------------------------------------
1 | package tool
2 |
3 | import (
4 | "os"
5 | "os/exec"
6 | "runtime"
7 | "strings"
8 | )
9 |
10 | var (
11 | SystemType string
12 | CommandType string
13 | CommandArgs string
14 | CmdRun string
15 | GateKeeperPath string = gatekeeperPath()
16 | )
17 |
18 |
19 | func InitSystem() {
20 | SystemType = runtime.GOOS
21 | if SystemType == "windows"{
22 | CommandType = "cmd"
23 | CommandArgs = "/C"
24 | CmdRun = "SET GO111MODULE=on&& SET GOPROXY=https://goproxy.cn"
25 | } else {
26 | CommandType = "sh"
27 | CommandArgs = "-c"
28 | CmdRun = "export GO111MODULE=on && export GOPROXY=https://goproxy.cn"
29 | }
30 | }
31 |
32 | func Cmd(command string) (string, error){
33 | LogInfo.Println(command)
34 | cmd := exec.Command(CommandType, CommandArgs, command)
35 | str, err := cmd.Output()
36 | LogInfo.Println(string(str))
37 | return string(str), err
38 | }
39 |
40 |
41 | func RunCmd(command string) error{
42 | cmd := exec.Command(CommandType, CommandArgs, command)
43 | // 命令的错误输出和标准输出都连接到同一个管道
44 | stdout, err := cmd.StdoutPipe()
45 | cmd.Stderr = cmd.Stdout
46 |
47 | if err != nil {
48 | return err
49 | }
50 | if err = cmd.Start(); err != nil {
51 | return err
52 | }
53 |
54 | // 从管道中实时获取输出并打印到终端
55 | for {
56 | tmp := make([]byte, 1024)
57 | _, err := stdout.Read(tmp)
58 | LogInfo.Println(string(tmp))
59 | if err != nil {
60 | break
61 | }
62 | }
63 |
64 | if err = cmd.Wait(); err != nil {
65 | return err
66 | }
67 | return nil
68 | }
69 |
70 |
71 | func GetCurrentPath() string{
72 | path, _ := os.Getwd()
73 | return strings.Replace(path, "\\", "/", -1)
74 | }
75 |
76 |
77 | func gatekeeperPath() string{
78 | path := GetCurrentPath()
79 | pathArr := strings.Split(path, "/")
80 | index := len(pathArr)
81 | pathArr = pathArr[0:index-1]
82 | path = strings.Join(pathArr, "/")
83 | return path
84 | }
--------------------------------------------------------------------------------
/install/tool/zip.go:
--------------------------------------------------------------------------------
1 | package tool
2 |
3 | import (
4 | "archive/zip"
5 | "io"
6 | "os"
7 | "path/filepath"
8 | )
9 |
10 |
11 | func Zip(srcFile string, destZip string) error {
12 | zipfile, err := os.Create(destZip)
13 | if err != nil {
14 | return err
15 | }
16 | defer zipfile.Close()
17 |
18 | archive := zip.NewWriter(zipfile)
19 | defer archive.Close()
20 |
21 | filepath.Walk(srcFile, func(path string, info os.FileInfo, err error) error {
22 | if err != nil {
23 | return err
24 | }
25 |
26 | header, err := zip.FileInfoHeader(info)
27 | if err != nil {
28 | return err
29 | }
30 |
31 | header.Name = path
32 | if info.IsDir() {
33 | header.Name += "/"
34 | } else {
35 | header.Method = zip.Deflate
36 | }
37 |
38 | writer, err := archive.CreateHeader(header)
39 | if err != nil {
40 | return err
41 | }
42 |
43 | if ! info.IsDir() {
44 | file, err := os.Open(path)
45 | if err != nil {
46 | return err
47 | }
48 | defer file.Close()
49 | _, err = io.Copy(writer, file)
50 | }
51 | return err
52 | })
53 |
54 | return err
55 | }
56 |
57 |
58 | func Unzip(zipFile string, destDir string) error {
59 | zipReader, err := zip.OpenReader(zipFile)
60 | if err != nil {
61 | return err
62 | }
63 | defer zipReader.Close()
64 |
65 | for _, f := range zipReader.File {
66 | fpath := filepath.Join(destDir, f.Name)
67 | if f.FileInfo().IsDir() {
68 | os.MkdirAll(fpath, os.ModePerm)
69 | } else {
70 | if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
71 | return err
72 | }
73 |
74 | inFile, err := f.Open()
75 | if err != nil {
76 | return err
77 | }
78 | defer inFile.Close()
79 |
80 | outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
81 | if err != nil {
82 | return err
83 | }
84 | defer outFile.Close()
85 |
86 | _, err = io.Copy(outFile, inFile)
87 | if err != nil {
88 | return err
89 | }
90 | }
91 | }
92 | return nil
93 | }
94 |
95 |
--------------------------------------------------------------------------------
/k8s_dashboard.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: go-gateteway-dashboard
5 | spec:
6 | replicas: 1
7 | selector:
8 | matchLabels:
9 | name: go-gateteway-dashboard
10 | template:
11 | metadata:
12 | labels:
13 | name: go-gateteway-dashboard
14 | spec:
15 | containers:
16 | - name: go-gateteway-dashboard
17 | image: go-gateteway-dashboard
18 | imagePullPolicy: Never
19 | ports:
20 | - containerPort: 8880
21 | ---
22 | apiVersion: v1
23 | kind: Service
24 | metadata:
25 | name: go-gateteway-dashboard
26 | spec:
27 | ports:
28 | - port: 8880
29 | name: "dashboard"
30 | targetPort: 8880
31 | protocol: TCP
32 | nodePort: 30088
33 | type: NodePort
34 | selector:
35 | name: go-gateteway-dashboard
--------------------------------------------------------------------------------
/k8s_server.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: go-gateteway-server
5 | spec:
6 | replicas: 3
7 | selector:
8 | matchLabels:
9 | name: go-gateteway-server
10 | template:
11 | metadata:
12 | labels:
13 | name: go-gateteway-server
14 | spec:
15 | containers:
16 | - name: go-gateteway-server
17 | image: go-gateteway-server:latest
18 | imagePullPolicy: Never
19 | ports:
20 | - containerPort: 8080
21 | - containerPort: 4433
22 | ---
23 | apiVersion: v1
24 | kind: Service
25 | metadata:
26 | name: go-gateteway-server
27 | spec:
28 | ports:
29 | - port: 8080
30 | name: "http"
31 | targetPort: 8080
32 | protocol: TCP
33 | nodePort: 30080
34 | - port: 4433
35 | name: "https"
36 | targetPort: 4433
37 | protocol: TCP
38 | nodePort: 30443
39 | type: NodePort
40 | selector:
41 | name: go-gateteway-server
--------------------------------------------------------------------------------
/load_balance/consistent_hash_strategy_test.go:
--------------------------------------------------------------------------------
1 | package load_balance
2 |
--------------------------------------------------------------------------------
/load_balance/loadbalance_config.go:
--------------------------------------------------------------------------------
1 | package load_balance
2 |
3 | import "github.com/didi/gatekeeper/model"
4 |
5 | type LoadBalanceConf interface {
6 | Attach(o Observer)
7 | GetConf() []string
8 | WatchConf()
9 | UpdateConf(conf []string)
10 | CloseWatch()
11 | }
12 |
13 | type Observer interface {
14 | Update()
15 | }
16 |
17 | type CheckConfigHandler func(service *model.ServiceDetail) (LoadBalanceConf, error)
18 |
19 | var CheckConfigHandlerMap map[string]CheckConfigHandler
20 |
21 | func RegisterCheckConfigHandler(lbtype string, conf CheckConfigHandler) {
22 | if CheckConfigHandlerMap == nil {
23 | CheckConfigHandlerMap = map[string]CheckConfigHandler{}
24 | }
25 | CheckConfigHandlerMap[lbtype] = conf
26 | }
27 |
28 | func GetCheckConfigHandler(lbtype string) CheckConfigHandler {
29 | if CheckConfigHandlerMap == nil {
30 | return nil
31 | }
32 | handler, ok := CheckConfigHandlerMap[lbtype]
33 | if !ok {
34 | return CheckConfigHandlerMap["upstream_config"]
35 | }
36 | return handler
37 | }
38 |
--------------------------------------------------------------------------------
/load_balance/loadbalance_config_test.go:
--------------------------------------------------------------------------------
1 | package load_balance
2 |
--------------------------------------------------------------------------------
/load_balance/loadbalance_strategy.go:
--------------------------------------------------------------------------------
1 | package load_balance
2 |
3 | import (
4 | "strings"
5 | )
6 |
7 | type LoadBalanceStrategy interface {
8 | Add(...string) error
9 | RemoveAll() error
10 | GetAll() ([]string, error)
11 | Get(string) (string, error)
12 | }
13 |
14 | type LoadBalance struct {
15 | strategy LoadBalanceStrategy
16 | conf LoadBalanceConf
17 | }
18 |
19 | func (r *LoadBalance) Add(params ...string) error {
20 | r.strategy.Add(params...)
21 | return nil
22 | }
23 |
24 | func (r *LoadBalance) Get(params string) (string, error) {
25 | return r.strategy.Get(params)
26 | }
27 |
28 | func (r *LoadBalance) GetAll() ([]string, error) {
29 | return r.strategy.GetAll()
30 | }
31 |
32 | func (r *LoadBalance) Update() {
33 | r.strategy.RemoveAll()
34 | for _, ip := range r.conf.GetConf() {
35 | r.strategy.Add(strings.Split(ip, ",")...)
36 | }
37 | }
38 |
39 | func (r *LoadBalance) Close() {
40 | r.conf.CloseWatch()
41 | }
42 |
43 | func NewLoadBalance(strategy LoadBalanceStrategy, conf LoadBalanceConf) *LoadBalance {
44 | return &LoadBalance{
45 | strategy: strategy,
46 | conf: conf,
47 | }
48 | }
49 |
50 | func LoadBanlanceFactorWithStrategy(strategy LoadBalanceStrategy, conf LoadBalanceConf) *LoadBalance {
51 | lb := NewLoadBalance(strategy, conf)
52 | conf.Attach(lb)
53 | lb.Update()
54 | return lb
55 | }
56 |
57 | type LoadBalanceStrategyHandler func() LoadBalanceStrategy
58 |
59 | var LoadBalanceStrategyHandlerMap map[string]LoadBalanceStrategyHandler
60 |
61 | func RegisterLoadBalanceStrategyHandler(name string, handler LoadBalanceStrategyHandler) {
62 | if LoadBalanceStrategyHandlerMap == nil {
63 | LoadBalanceStrategyHandlerMap = map[string]LoadBalanceStrategyHandler{}
64 | }
65 | LoadBalanceStrategyHandlerMap[name] = handler
66 | }
67 |
68 | func GetLoadBalanceStrategy(name string) LoadBalanceStrategy {
69 | if LoadBalanceStrategyHandlerMap == nil {
70 | return nil
71 | }
72 | handler := LoadBalanceStrategyHandlerMap[name]
73 | return handler()
74 | }
75 |
--------------------------------------------------------------------------------
/load_balance/random_strategy.go:
--------------------------------------------------------------------------------
1 | package load_balance
2 |
3 | import (
4 | "errors"
5 | "math/rand"
6 | )
7 |
8 | type RandomStrategy struct {
9 | curIndex int
10 | rss []string
11 | }
12 |
13 | func (r *RandomStrategy) Add(params ...string) error {
14 | if len(params) == 0 {
15 | return errors.New("param len 1 at least")
16 | }
17 | addr := params[0]
18 | r.rss = append(r.rss, addr)
19 | return nil
20 | }
21 |
22 | func (r *RandomStrategy) Next() string {
23 | if len(r.rss) == 0 {
24 | return ""
25 | }
26 | r.curIndex = rand.Intn(len(r.rss))
27 | return r.rss[r.curIndex]
28 | }
29 |
30 | func (r *RandomStrategy) Get(key string) (string, error) {
31 | return r.Next(), nil
32 | }
33 |
34 | func (r *RandomStrategy) GetAll() ([]string, error) {
35 | return r.rss, nil
36 | }
37 |
38 | func (r *RandomStrategy) RemoveAll() error {
39 | r.rss = []string{}
40 | return nil
41 | }
42 |
43 | func init() {
44 | RegisterLoadBalanceStrategyHandler("random", func() LoadBalanceStrategy {
45 | return &RandomStrategy{}
46 | })
47 | }
48 |
--------------------------------------------------------------------------------
/load_balance/random_strategy_test.go:
--------------------------------------------------------------------------------
1 | package load_balance
2 |
--------------------------------------------------------------------------------
/load_balance/round_robin_strategy.go:
--------------------------------------------------------------------------------
1 | package load_balance
2 |
3 | import (
4 | "errors"
5 | )
6 |
7 | type RoundRobinStrategy struct {
8 | curIndex int
9 | rss []string
10 | }
11 |
12 | func (r *RoundRobinStrategy) Add(params ...string) error {
13 | if len(params) == 0 {
14 | return errors.New("param len 1 at least")
15 | }
16 | addr := params[0]
17 | r.rss = append(r.rss, addr)
18 | return nil
19 | }
20 |
21 | func (r *RoundRobinStrategy) Next() string {
22 | if len(r.rss) == 0 {
23 | return ""
24 | }
25 | lens := len(r.rss) //5
26 | if r.curIndex >= lens {
27 | r.curIndex = 0
28 | }
29 | curAddr := r.rss[r.curIndex]
30 | r.curIndex = (r.curIndex + 1) % lens
31 | return curAddr
32 | }
33 |
34 | func (r *RoundRobinStrategy) Get(key string) (string, error) {
35 | return r.Next(), nil
36 | }
37 |
38 | func (r *RoundRobinStrategy) GetAll() ([]string, error) {
39 | return r.rss, nil
40 | }
41 |
42 | func (r *RoundRobinStrategy) RemoveAll() error {
43 | r.rss = []string{}
44 | return nil
45 | }
46 |
47 | func init() {
48 | RegisterLoadBalanceStrategyHandler("round", func() LoadBalanceStrategy {
49 | return &RoundRobinStrategy{}
50 | })
51 | }
52 |
--------------------------------------------------------------------------------
/load_balance/round_robin_strategy_test.go:
--------------------------------------------------------------------------------
1 | package load_balance
2 |
3 | import "testing"
4 |
5 | func TestRoundRobinStrategy_Add(t *testing.T) {
6 | type fields struct {
7 | curIndex int
8 | rss []string
9 | }
10 | type args struct {
11 | params []string
12 | }
13 | tests := []struct {
14 | name string
15 | fields fields
16 | args args
17 | wantErr bool
18 | }{
19 | // TODO: Add test cases.
20 | }
21 | for _, tt := range tests {
22 | t.Run(tt.name, func(t *testing.T) {
23 | r := &RoundRobinStrategy{
24 | curIndex: tt.fields.curIndex,
25 | rss: tt.fields.rss,
26 | }
27 | if err := r.Add(tt.args.params...); (err != nil) != tt.wantErr {
28 | t.Errorf("Add() error = %v, wantErr %v", err, tt.wantErr)
29 | }
30 | })
31 | }
32 | }
--------------------------------------------------------------------------------
/load_balance/weight_round_strategy.go:
--------------------------------------------------------------------------------
1 | package load_balance
2 |
3 | import (
4 | "errors"
5 | "strconv"
6 | )
7 |
8 | type WeightRoundRobinStrategy struct {
9 | curIndex int
10 | rss []*WeightNode
11 | rsw []int
12 | conf LoadBalanceConf
13 | }
14 |
15 | type WeightNode struct {
16 | addr string
17 | weight int //权重值
18 | currentWeight int //节点当前权重
19 | effectiveWeight int //有效权重
20 | }
21 |
22 | func (r *WeightRoundRobinStrategy) Add(params ...string) error {
23 | if len(params) != 2 {
24 | return errors.New("param len need 2")
25 | }
26 | parInt, err := strconv.ParseInt(params[1], 10, 64)
27 | if err != nil {
28 | return err
29 | }
30 | node := &WeightNode{addr: params[0], weight: int(parInt)}
31 | node.effectiveWeight = node.weight
32 | r.rss = append(r.rss, node)
33 | return nil
34 | }
35 |
36 | func (r *WeightRoundRobinStrategy) Next() string {
37 | total := 0
38 | var best *WeightNode
39 | for i := 0; i < len(r.rss); i++ {
40 | w := r.rss[i]
41 | total += w.effectiveWeight
42 | w.currentWeight += w.effectiveWeight
43 | if w.effectiveWeight < w.weight {
44 | w.effectiveWeight++
45 | }
46 | if best == nil || w.currentWeight > best.currentWeight {
47 | best = w
48 | }
49 | }
50 | if best == nil {
51 | return ""
52 | }
53 | best.currentWeight -= total
54 | return best.addr
55 | }
56 |
57 | func (r *WeightRoundRobinStrategy) Get(key string) (string, error) {
58 | return r.Next(), nil
59 | }
60 |
61 | func (r *WeightRoundRobinStrategy) GetAll() ([]string, error) {
62 | iplist := []string{}
63 | for _, item := range r.rss {
64 | iplist = append(iplist, item.addr)
65 | }
66 | return iplist, nil
67 | }
68 |
69 | func (r *WeightRoundRobinStrategy) RemoveAll() error {
70 | r.rss = []*WeightNode{}
71 | r.rsw = []int{}
72 | return nil
73 | }
74 |
75 | func init() {
76 | RegisterLoadBalanceStrategyHandler("weight_round", func() LoadBalanceStrategy {
77 | return &WeightRoundRobinStrategy{}
78 | })
79 | }
80 |
--------------------------------------------------------------------------------
/load_balance/weight_round_strategy_test.go:
--------------------------------------------------------------------------------
1 | package load_balance
2 |
--------------------------------------------------------------------------------
/model/admin_dto.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "github.com/didi/gatekeeper/public"
5 | "github.com/gin-gonic/gin"
6 | "time"
7 | )
8 |
9 | type AdminInfoOutput struct {
10 | ID int `json:"id"`
11 | Name string `json:"name"`
12 | LoginTime time.Time `json:"login_time"`
13 | Avatar string `json:"avatar"`
14 | Introduction string `json:"introduction"`
15 | Roles []string `json:"roles"`
16 | }
17 |
18 | type ChangePwdInput struct {
19 | Password string `json:"password" form:"password" comment:"密码" example:"123456" validate:"required"` //密码
20 | }
21 |
22 | func (param *ChangePwdInput) BindValidParam(c *gin.Context) error {
23 | return public.DefaultGetValidParams(c, param)
24 | }
25 |
--------------------------------------------------------------------------------
/model/admin_login_dto.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "github.com/didi/gatekeeper/public"
5 | "github.com/gin-gonic/gin"
6 | "time"
7 | )
8 |
9 | type AdminSessionInfo struct {
10 | ID int `json:"id"`
11 | UserName string `json:"user_name"`
12 | LoginTime time.Time `json:"login_time"`
13 | }
14 |
15 | type AdminLoginInput struct {
16 | UserName string `json:"username" form:"username" comment:"管理员用户名" example:"admin" validate:"required,valid_username"` //管理员用户名
17 | Password string `json:"password" form:"password" comment:"密码" example:"123456" validate:"required"` //密码
18 | }
19 |
20 | func (param *AdminLoginInput) BindValidParam(c *gin.Context) error {
21 | return public.DefaultGetValidParams(c, param)
22 | }
23 |
24 | type AdminLoginOutput struct {
25 | Token string `json:"token" form:"token" comment:"token" example:"token" validate:""` //token
26 | }
27 |
--------------------------------------------------------------------------------
/model/admin_model.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "github.com/didi/gatekeeper/public"
5 | "github.com/e421083458/gorm"
6 | "github.com/gin-gonic/gin"
7 | "github.com/pkg/errors"
8 | "time"
9 | )
10 |
11 | type Admin struct {
12 | Id int `json:"id" gorm:"primary_key" description:"自增主键"`
13 | UserName string `json:"user_name" gorm:"column:user_name" description:"管理员用户名"`
14 | Salt string `json:"salt" gorm:"column:salt" description:"盐"`
15 | Password string `json:"password" gorm:"column:password" description:"密码"`
16 | UpdatedAt time.Time `json:"update_at" gorm:"column:update_at" description:"更新时间"`
17 | CreatedAt time.Time `json:"create_at" gorm:"column:create_at" description:"创建时间"`
18 | IsDelete int `json:"is_delete" gorm:"column:is_delete" description:"是否删除"`
19 | }
20 |
21 | func (t *Admin) TableName() string {
22 | return "gateway_admin"
23 | }
24 |
25 | func (t *Admin) LoginCheck(c *gin.Context, tx *gorm.DB, param *AdminLoginInput) (*Admin, error) {
26 | adminInfo, err := t.Find(c, tx, (&Admin{UserName: param.UserName, IsDelete: 0}))
27 | if err != nil {
28 | return nil, errors.New("用户信息不存在")
29 | }
30 | saltPassword := public.GenSaltPassword(adminInfo.Salt, param.Password)
31 | if adminInfo.Password != saltPassword {
32 | return nil, errors.New("密码错误,请重新输入")
33 | }
34 | return adminInfo, nil
35 | }
36 |
37 | func (t *Admin) Find(c *gin.Context, tx *gorm.DB, search *Admin) (*Admin, error) {
38 | out := &Admin{}
39 | err := tx.SetCtx(public.GetGinTraceContext(c)).Where(search).Find(out).Error
40 | if err != nil {
41 | return nil, err
42 | }
43 | return out, nil
44 | }
45 |
46 | func (t *Admin) Save(c *gin.Context, tx *gorm.DB) error {
47 | return tx.SetCtx(public.GetGinTraceContext(c)).Save(t).Error
48 | }
49 |
--------------------------------------------------------------------------------
/model/dashboard_dto.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | type PanelGroupDataOutput struct {
4 | ServiceNum int64 `json:"serviceNum"`
5 | AppNum int64 `json:"appNum"`
6 | CurrentQPS int64 `json:"currentQps"`
7 | TodayRequestNum int64 `json:"todayRequestNum"`
8 | }
9 |
10 | type DashServiceStatItemOutput struct {
11 | Name string `json:"name"`
12 | LoadType int `json:"load_type"`
13 | Value int64 `json:"value"`
14 | }
15 |
16 | type DashServiceStatOutput struct {
17 | Legend []string `json:"legend"`
18 | Data []DashServiceStatItemOutput `json:"data"`
19 | }
--------------------------------------------------------------------------------
/model/oauth_dto.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "github.com/didi/gatekeeper/public"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | type TokensInput struct {
9 | GrantType string `json:"grant_type" form:"grant_type" comment:"授权类型" example:"client_credentials" validate:"required"` //授权类型
10 | Scope string `json:"scope" form:"scope" comment:"权限范围" example:"read_write" validate:"required"` //权限范围
11 | }
12 |
13 | func (param *TokensInput) BindValidParam(c *gin.Context) error {
14 | return public.DefaultGetValidParams(c, param)
15 | }
16 |
17 | type TokensOutput struct {
18 | AccessToken string `json:"access_token" form:"access_token"` //access_token
19 | ExpiresIn int `json:"expires_in" form:"expires_in"` //expires_in
20 | TokenType string `json:"token_type" form:"token_type"` //token_type
21 | Scope string `json:"scope" form:"scope"` //scope
22 | }
--------------------------------------------------------------------------------
/model/service_detail_model.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "errors"
5 | "regexp"
6 | "strings"
7 |
8 | "github.com/bitly/go-simplejson"
9 | "github.com/didi/gatekeeper/public"
10 | "github.com/gin-gonic/gin"
11 | )
12 |
13 | type ServiceDetail struct {
14 | Info *ServiceInfo `json:"info" description:"基本信息"`
15 | PluginConf *simplejson.Json `json:"plugin_conf" description:"plugin_conf"`
16 | }
17 |
18 | type UpstreamConfig struct {
19 | Schema string
20 | IpList []string
21 | IpWeight map[string]string
22 | }
23 |
24 | func GetUpstreamConfigFromString(upstreamList string) (*UpstreamConfig, error) {
25 | config := &UpstreamConfig{}
26 | if upstreamList == "" {
27 | return config, nil
28 | }
29 | tmpLine := strings.Split(upstreamList, "\n")
30 | ipList := []string{}
31 | ipConf := map[string]string{}
32 | for _, tmp := range tmpLine {
33 | r, _ := regexp.Compile("^(.*://)(.*?)\\s(.*?)$")
34 | submatch := r.FindStringSubmatch(tmp)
35 | if len(submatch) != 4 {
36 | return nil, errors.New("upstream_list format error")
37 | }
38 | config.Schema = submatch[1]
39 | ipList = append(ipList, submatch[2])
40 | ipConf[submatch[2]] = submatch[3]
41 | }
42 | config.IpList = ipList
43 | config.IpWeight = ipConf
44 | return config, nil
45 | }
46 |
47 | func GetServiceDetailFromGinContext(c *gin.Context) (*ServiceDetail, error) {
48 | serverInterface, ok := c.Get(public.ServiceDetailContextKey)
49 | if !ok {
50 | return nil, errors.New("service not found")
51 | }
52 | return serverInterface.(*ServiceDetail), nil
53 | }
54 |
--------------------------------------------------------------------------------
/public/const.go:
--------------------------------------------------------------------------------
1 | package public
2 |
3 | const (
4 | ValidatorKey = "ValidatorKey"
5 | TranslatorKey = "TranslatorKey"
6 | AdminSessionInfoKey = "AdminSessionInfoKey"
7 |
8 | LoadTypeHTTP = 0
9 | LoadTypeTCP = 1
10 | LoadTypeGRPC = 2
11 |
12 | HTTPRuleTypePrefixURL = 0
13 | HTTPRuleTypeDomain = 1
14 |
15 | //flow_counter_store
16 | RedisFlowDayKey = "flow_day_count"
17 | RedisFlowHourKey = "flow_hour_count"
18 |
19 | //flow_limit && http_flow_limit function app&server's name or prefix
20 | FlowTotal = "flow_total"
21 | FlowServicePrefix = "flow_service_"
22 | FlowAppPrefix = "flow_app_"
23 |
24 | //distributed limter prefix
25 | DistributedLimiterPrefix = "dist_limiter_"
26 |
27 | JwtSignKey = "my_sign_key"
28 | JwtExpires = 60 * 60
29 |
30 | //middleware context key
31 | ServiceDetailContextKey = "service"
32 | )
33 |
34 | var (
35 | LoadTypeMap = map[int]string{
36 | LoadTypeHTTP: "HTTP",
37 | LoadTypeTCP: "TCP",
38 | LoadTypeGRPC: "GRPC",
39 | }
40 | )
41 |
--------------------------------------------------------------------------------
/public/http_response.go:
--------------------------------------------------------------------------------
1 | package public
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "github.com/gin-gonic/gin"
7 | "strings"
8 | )
9 |
10 | type ResponseCode int
11 |
12 | //1000以下为通用码,1000以上为用户自定义码
13 | const (
14 | SuccessCode ResponseCode = iota
15 | UndefErrorCode
16 | ValidErrorCode
17 | InternalErrorCode
18 | InvalidRequestErrorCode ResponseCode = 401
19 | CustomizeCode ResponseCode = 1000
20 | GROUPALL_SAVE_FLOWERROR ResponseCode = 2001
21 | )
22 |
23 | type Response struct {
24 | ErrorCode ResponseCode `json:"errno"`
25 | ErrorMsg string `json:"errmsg"`
26 | Data interface{} `json:"data"`
27 | TraceId interface{} `json:"trace_id"`
28 | Stack interface{} `json:"stack"`
29 | }
30 |
31 | func ResponseError(c *gin.Context, code ResponseCode, err error) {
32 | traceContext := GetGinTraceContext(c)
33 | errMsg := fmt.Sprintf("%+v", err)
34 |
35 | straceMsg := ""
36 | tmpStack := strings.Split(errMsg, "||")
37 | if len(tmpStack) == 2 {
38 | errMsg = tmpStack[0]
39 | straceMsg = tmpStack[1]
40 | }
41 | strackList := strings.Split(straceMsg, "\n")
42 | for i, t := range strackList {
43 | t = strings.Replace(t, "\t", " ", -1)
44 | strackList[i] = t
45 | }
46 | resp := &Response{ErrorCode: code, ErrorMsg: errMsg, Data: "", TraceId: traceContext.TraceId, Stack: strackList}
47 | c.JSON(200, resp)
48 | response, _ := json.Marshal(resp)
49 | c.Set("response", string(response))
50 | c.AbortWithError(200, err)
51 | }
52 |
53 | func ResponseSuccess(c *gin.Context, data interface{}) {
54 | traceContext := GetGinTraceContext(c)
55 | resp := &Response{ErrorCode: SuccessCode, ErrorMsg: "", Data: data, TraceId: traceContext.TraceId}
56 | c.JSON(200, resp)
57 | response, _ := json.Marshal(resp)
58 | c.Set("response", string(response))
59 | }
60 |
--------------------------------------------------------------------------------
/public/jwt.go:
--------------------------------------------------------------------------------
1 | package public
2 |
3 | import (
4 | "errors"
5 | "github.com/dgrijalva/jwt-go"
6 | )
7 |
8 | func JwtDecode(tokenString string) (*jwt.StandardClaims, error) {
9 | token, err := jwt.ParseWithClaims(tokenString, &jwt.StandardClaims{}, func(token *jwt.Token) (interface{}, error) {
10 | return []byte(JwtSignKey), nil
11 | })
12 | if err != nil {
13 | return nil, err
14 | }
15 | if claims, ok := token.Claims.(*jwt.StandardClaims); ok {
16 | return claims, nil
17 | } else {
18 | return nil, errors.New("token is not jwt.StandardClaims")
19 | }
20 | }
21 |
22 | func JwtEncode(claims jwt.StandardClaims) (string, error) {
23 | mySigningKey := []byte(JwtSignKey)
24 | token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
25 | return token.SignedString(mySigningKey)
26 | }
27 |
--------------------------------------------------------------------------------
/public/log.go:
--------------------------------------------------------------------------------
1 | package public
2 |
3 | import (
4 | "github.com/didi/gatekeeper/golang_common/lib"
5 | "github.com/didi/gatekeeper/golang_common/trace"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | func GinLogNotice(c *gin.Context, dltag string, m map[string]interface{}) {
10 | traceContext := GetGinTraceContext(c)
11 | lib.Log.TagInfo(traceContext, dltag, m)
12 | }
13 |
14 | func GinLogWarning(c *gin.Context, dltag string, m map[string]interface{}) {
15 | traceContext := GetGinTraceContext(c)
16 | lib.Log.TagError(traceContext, dltag, m)
17 | }
18 |
19 | func GetGinTraceContext(c *gin.Context) *trace.Trace {
20 | traceContext, exists := trace.GetCtxTrace(c.Request.Context())
21 | if exists {
22 | return traceContext
23 | }
24 | return trace.New(c.Request)
25 | }
--------------------------------------------------------------------------------
/public/redis.go:
--------------------------------------------------------------------------------
1 | package public
2 |
3 | import (
4 | "github.com/didi/gatekeeper/golang_common/lib"
5 | "github.com/garyburd/redigo/redis"
6 | )
7 |
8 | func RedisConfPipline(pip ...func(c redis.Conn)) error {
9 | c, err := lib.RedisConnFactory("default")
10 | if err != nil {
11 | return err
12 | }
13 | defer c.Close()
14 | for _, f := range pip {
15 | f(c)
16 | }
17 | c.Flush()
18 | return nil
19 | }
20 |
21 | func RedisConfDo(commandName string, args ...interface{}) (interface{}, error) {
22 | c, err := lib.RedisConnFactory("default")
23 | if err != nil {
24 | return nil, err
25 | }
26 | defer c.Close()
27 | return c.Do(commandName, args...)
28 | }
29 |
--------------------------------------------------------------------------------
/reverse_proxy/grcp_reverse_proxy.go:
--------------------------------------------------------------------------------
1 | package reverse_proxy
2 |
3 | import (
4 | "context"
5 | "github.com/didi/gatekeeper/load_balance"
6 | "github.com/e421083458/grpc-proxy/proxy"
7 | "google.golang.org/grpc"
8 | "google.golang.org/grpc/metadata"
9 | "log"
10 | )
11 |
12 | func NewGrpcLoadBalanceHandler(lb *load_balance.LoadBalance) grpc.StreamHandler {
13 | return func() grpc.StreamHandler {
14 | nextAddr, err := lb.Get("")
15 | if err != nil {
16 | log.Fatal("get next addr fail")
17 | }
18 | director := func(ctx context.Context, fullMethodName string) (context.Context, *grpc.ClientConn, error) {
19 | c, err := grpc.DialContext(ctx, nextAddr, grpc.WithCodec(proxy.Codec()), grpc.WithInsecure())
20 | md, _ := metadata.FromIncomingContext(ctx)
21 | outCtx, _ := context.WithCancel(ctx)
22 | outCtx = metadata.NewOutgoingContext(outCtx, md.Copy())
23 | return outCtx, c, err
24 | }
25 | return proxy.TransparentHandler(director)
26 | }()
27 | }
28 |
--------------------------------------------------------------------------------
/reverse_proxy/http_reverse_proxy.go:
--------------------------------------------------------------------------------
1 | package reverse_proxy
2 |
3 | import (
4 | "bytes"
5 | "github.com/didi/gatekeeper/dashboard_middleware"
6 | "github.com/didi/gatekeeper/load_balance"
7 | "github.com/gin-gonic/gin"
8 | "net/http"
9 | "net/http/httputil"
10 | "net/url"
11 | "strings"
12 | )
13 |
14 | func NewLoadBalanceReverseProxy(c *gin.Context, lb *load_balance.LoadBalance, trans *http.Transport) *httputil.ReverseProxy {
15 | director := func(req *http.Request) {
16 | nextAddr, err := lb.Get(req.URL.String())
17 | if err != nil || nextAddr == "" {
18 | panic("get next addr fail")
19 | }
20 | target, err := url.Parse(nextAddr)
21 | if err != nil {
22 | panic(err)
23 | }
24 | targetQuery := target.RawQuery
25 | req.URL.Scheme = target.Scheme
26 | req.URL.Host = target.Host
27 | req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path)
28 | req.Host = target.Host
29 | if targetQuery == "" || req.URL.RawQuery == "" {
30 | buffer := bytes.NewBufferString(targetQuery)
31 | buffer.WriteString(req.URL.RawQuery)
32 | req.URL.RawQuery = buffer.String()
33 | } else {
34 | buffer := bytes.NewBufferString(targetQuery)
35 | buffer.WriteString("&")
36 | buffer.WriteString(req.URL.RawQuery)
37 | req.URL.RawQuery = buffer.String()
38 | }
39 | }
40 | errFunc := func(w http.ResponseWriter, r *http.Request, err error) {
41 | dashboard_middleware.ResponseError(c, 999, err)
42 | }
43 | return &httputil.ReverseProxy{Director: director, Transport: trans, ErrorHandler: errFunc}
44 | }
45 |
46 | func singleJoiningSlash(a, b string) string {
47 | aslash := strings.HasSuffix(a, "/")
48 | bslash := strings.HasPrefix(b, "/")
49 | switch {
50 | case aslash && bslash:
51 | buffer := bytes.NewBufferString(a)
52 | buffer.WriteString(b[1:])
53 | return buffer.String()
54 | case !aslash && !bslash:
55 | buffer := bytes.NewBufferString(a)
56 | buffer.WriteString("/")
57 | buffer.WriteString(b)
58 | return buffer.String()
59 | }
60 | buffer := bytes.NewBufferString(a)
61 | buffer.WriteString(b)
62 | return buffer.String()
63 | }
64 |
--------------------------------------------------------------------------------
/tcp_proxy_middleware/tcp_black_list.go:
--------------------------------------------------------------------------------
1 | package tcp_proxy_middleware
2 |
3 | import (
4 | "fmt"
5 | "github.com/didi/gatekeeper/public"
6 | "strings"
7 | )
8 |
9 | //匹配接入方式 基于请求信息
10 | func TCPBlackListMiddleware() func(c *TcpSliceRouterContext) {
11 | return func(c *TcpSliceRouterContext) {
12 | serviceDetail, err := c.GetServiceDetail()
13 | if err != nil {
14 | c.conn.Write([]byte(err.Error()))
15 | c.Abort()
16 | return
17 | }
18 | whiteListStr := serviceDetail.PluginConf.GetPath("tcp_whiteblacklist", "ip_white_list").MustString()
19 | blackListStr := serviceDetail.PluginConf.GetPath("tcp_whiteblacklist", "ip_black_list").MustString()
20 | if blackListStr == "" {
21 | c.Next()
22 | return
23 | }
24 |
25 | splits := strings.Split(c.conn.RemoteAddr().String(), ":")
26 | clientIP := ""
27 | if len(splits) == 2 {
28 | clientIP = splits[0]
29 | }
30 |
31 | if whiteListStr == "" && blackListStr != "" {
32 | if public.InIPSliceStr(clientIP, blackListStr) {
33 | c.conn.Write([]byte(fmt.Sprintf("%s in black ip list", clientIP)))
34 | c.Abort()
35 | return
36 | }
37 | }
38 | c.Next()
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/tcp_proxy_middleware/tcp_flow_count.go:
--------------------------------------------------------------------------------
1 | package tcp_proxy_middleware
2 |
3 | import (
4 | "github.com/didi/gatekeeper/handler"
5 | "github.com/didi/gatekeeper/public"
6 | )
7 |
8 | func TCPFlowCountMiddleware() func(c *TcpSliceRouterContext) {
9 | return func(c *TcpSliceRouterContext) {
10 | serviceDetail,err := c.GetServiceDetail()
11 | if err != nil {
12 | c.conn.Write([]byte(err.Error()))
13 | c.Abort()
14 | return
15 | }
16 | totalCounter, err := handler.ServiceCounterHandler.GetCounter(public.FlowTotal)
17 | if err != nil {
18 | c.conn.Write([]byte(err.Error()))
19 | c.Abort()
20 | return
21 | }
22 | totalCounter.Increase()
23 |
24 | serviceCounter, err := handler.ServiceCounterHandler.GetCounter(public.FlowServicePrefix + serviceDetail.Info.ServiceName)
25 | if err != nil {
26 | c.conn.Write([]byte(err.Error()))
27 | c.Abort()
28 | return
29 | }
30 | serviceCounter.Increase()
31 | c.Next()
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/tcp_proxy_middleware/tcp_flow_limit.go:
--------------------------------------------------------------------------------
1 | package tcp_proxy_middleware
2 |
3 | import (
4 | "fmt"
5 | "github.com/didi/gatekeeper/handler"
6 | "github.com/didi/gatekeeper/model"
7 | "github.com/didi/gatekeeper/public"
8 | "strings"
9 | )
10 |
11 | func TCPFlowLimitMiddleware() func(c *TcpSliceRouterContext) {
12 | return func(c *TcpSliceRouterContext) {
13 | serverInterface := c.Get("service")
14 | if serverInterface == nil {
15 | c.conn.Write([]byte("get service empty"))
16 | c.Abort()
17 | return
18 | }
19 | serviceDetail := serverInterface.(*model.ServiceDetail)
20 | serviceFlowNum := serviceDetail.PluginConf.GetPath("http_flow_limit","service_flow_limit_num").MustInt()
21 | serviceFlowType := serviceDetail.PluginConf.GetPath("http_flow_limit","service_flow_limit_type").MustInt()
22 | if serviceFlowNum != 0 {
23 | serviceLimiter, err := handler.FlowLimiterHandler.GetLimiter(
24 | public.FlowServicePrefix+serviceDetail.Info.ServiceName, float64(serviceFlowNum), serviceFlowType, true)
25 | if err != nil {
26 | c.conn.Write([]byte(err.Error()))
27 | c.Abort()
28 | return
29 | }
30 | if !serviceLimiter.Allow() {
31 | c.conn.Write([]byte(fmt.Sprintf("service flow limit %v", serviceFlowNum)))
32 | c.Abort()
33 | return
34 | }
35 | }
36 |
37 | splits := strings.Split(c.conn.RemoteAddr().String(), ":")
38 | clientIP := ""
39 | if len(splits) == 2 {
40 | clientIP = splits[0]
41 | }
42 | clientIpFlowNum := serviceDetail.PluginConf.GetPath("tcp_flow_limit","clientip_flow_limit_num").MustInt()
43 | clientIpFlowType := serviceDetail.PluginConf.GetPath("tcp_flow_limit","clientip_flow_limit_type").MustInt()
44 | if clientIpFlowNum > 0 {
45 | clientLimiter, err := handler.FlowLimiterHandler.GetLimiter(public.FlowServicePrefix+serviceDetail.Info.ServiceName+"_"+clientIP, float64(clientIpFlowNum), clientIpFlowType, true)
46 | if err != nil {
47 | c.conn.Write([]byte(err.Error()))
48 | c.Abort()
49 | return
50 | }
51 | if !clientLimiter.Allow() {
52 | c.conn.Write([]byte(fmt.Sprintf("%v flow limit %v", clientIP, clientIpFlowNum)))
53 | c.Abort()
54 | return
55 | }
56 | }
57 | c.Next()
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/tcp_proxy_middleware/tcp_white_list.go:
--------------------------------------------------------------------------------
1 | package tcp_proxy_middleware
2 |
3 | import (
4 | "fmt"
5 | "github.com/didi/gatekeeper/public"
6 | "strings"
7 | )
8 |
9 | //匹配接入方式 基于请求信息
10 | func TCPWhiteListMiddleware() func(c *TcpSliceRouterContext) {
11 | return func(c *TcpSliceRouterContext) {
12 | serviceDetail, err := c.GetServiceDetail()
13 | if err != nil {
14 | c.conn.Write([]byte(err.Error()))
15 | c.Abort()
16 | return
17 | }
18 |
19 | splits := strings.Split(c.conn.RemoteAddr().String(), ":")
20 | clientIP := ""
21 | if len(splits) == 2 {
22 | clientIP = splits[0]
23 | }
24 |
25 | whiteListStr := serviceDetail.PluginConf.GetPath("tcp_whiteblacklist", "ip_white_list").MustString()
26 | if whiteListStr != "" {
27 | if !public.InIPSliceStr(clientIP, whiteListStr) {
28 | c.conn.Write([]byte(fmt.Sprintf("%s not in white ip list", clientIP)))
29 | c.Abort()
30 | return
31 | }
32 | }
33 |
34 | c.Next()
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/tcp_server/tcp_conn.go:
--------------------------------------------------------------------------------
1 | package tcp_server
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "net"
7 | "runtime"
8 | )
9 |
10 | type tcpKeepAliveListener struct {
11 | *net.TCPListener
12 | }
13 |
14 | //todo 思考点:继承方法覆写方法时,只要使用非指针接口
15 | func (ln tcpKeepAliveListener) Accept() (net.Conn, error) {
16 | tc, err := ln.AcceptTCP()
17 | if err != nil {
18 | return nil, err
19 | }
20 | return tc, nil
21 | }
22 |
23 | type contextKey struct {
24 | name string
25 | }
26 |
27 | func (k *contextKey) String() string {
28 | return "tcp_proxy context value " + k.name
29 | }
30 |
31 | type conn struct {
32 | server *TcpServer
33 | cancelCtx context.CancelFunc
34 | rwc net.Conn
35 | remoteAddr string
36 | }
37 |
38 | func (c *conn) close() {
39 | c.rwc.Close()
40 | }
41 |
42 | func (c *conn) serve(ctx context.Context) {
43 | defer func() {
44 | if err := recover(); err != nil && err != ErrAbortHandler {
45 | const size = 64 << 10
46 | buf := make([]byte, size)
47 | buf = buf[:runtime.Stack(buf, false)]
48 | fmt.Printf("tcp: panic serving %v: %v\n%s", c.remoteAddr, err, buf)
49 | }
50 | c.close()
51 | }()
52 | c.remoteAddr = c.rwc.RemoteAddr().String()
53 | ctx = context.WithValue(ctx, LocalAddrContextKey, c.rwc.LocalAddr())
54 | if c.server.Handler == nil {
55 | panic("handler empty")
56 | }
57 | c.server.Handler.ServeTCP(ctx, c.rwc)
58 | }
59 |
--------------------------------------------------------------------------------
/test_suites/README.md:
--------------------------------------------------------------------------------
1 | # Integration test use document
2 | -1. The goconvey command must be installed to ensure that the command can be executed
3 | ```
4 | cd $GOPATH
5 | go get github.com/smartystreets/goconvey
6 | goconvey
7 | ```
8 |
9 | -2. Create a test database and import the data structure
10 | ```
11 | mysql -h 127.0.0.1 -u root -p -e "CREATE DATABASE gatekeeper_test DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;"
12 | mysql -h 127.0.0.1 -u root -p gatekeeper_test