├── .cargo └── config ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── Makefile ├── README.md ├── docker ├── .gitignore ├── Dockerfile.base ├── Dockerfile.build-alpine-nginx └── Dockerfile.module ├── mixer-ngx ├── Cargo.toml ├── snippets │ └── tools.MD └── src │ ├── .gitignore │ ├── encode.rs │ ├── lib.rs │ ├── message.rs │ ├── mixer_check.rs │ ├── mixer_report.rs │ ├── mixer_thread.rs │ └── ngx │ ├── config.rs │ ├── location_config.rs │ ├── main_config.rs │ ├── mod.rs │ ├── request.rs │ └── server_config.rs ├── mixer-tests ├── Cargo.toml ├── src │ ├── lib.rs │ └── util.rs └── tests │ ├── nginx_check_test.rs │ └── nginx_report_test.rs ├── mixer-transport ├── Cargo.toml ├── build.rs ├── src │ ├── attribute │ │ ├── attr_wrapper.rs │ │ ├── attr_wrapper_test.rs │ │ ├── global_dict.rs │ │ ├── global_dict_test.rs │ │ ├── message_dict.rs │ │ ├── message_dict_test.rs │ │ └── mod.rs │ ├── bin │ │ └── report_client.rs │ ├── istio_client │ │ ├── cache_elem.rs │ │ ├── check_cache.rs │ │ ├── check_cache_test.rs │ │ ├── check_options_test.rs │ │ ├── lru_cache.rs │ │ ├── mixer_client_wrapper.rs │ │ ├── mod.rs │ │ ├── options.rs │ │ ├── quota_cache.rs │ │ └── referenced.rs │ ├── lib.rs │ ├── mixer_grpc │ │ ├── .gitignore │ │ └── mod.rs │ └── transport │ │ ├── futures.rs │ │ ├── mixer_grpc.rs │ │ ├── mod.rs │ │ ├── server_info.rs │ │ ├── status.rs │ │ └── status_test.rs └── tests │ └── intg_transport_test.rs ├── module ├── config ├── config.make ├── ngx_http_istio_mixer_module.c └── release │ └── ngx_http_istio_mixer_module.so ├── nginx.mk ├── protobuf ├── gogoproto │ └── gogo.proto ├── google │ ├── protobuf │ │ ├── any.proto │ │ ├── descriptor.proto │ │ ├── duration.proto │ │ └── timestamp.proto │ └── rpc │ │ └── status.proto ├── mixer │ └── v1 │ │ ├── attributes.proto │ │ ├── check.proto │ │ ├── config │ │ └── client │ │ │ ├── api_spec.proto │ │ │ ├── auth.proto │ │ │ ├── client_config.proto │ │ │ ├── quota.proto │ │ │ └── service.proto │ │ ├── global_dictionary.yaml │ │ ├── report.proto │ │ └── service.proto └── proxy │ └── v1 │ └── config │ ├── dest_policy.proto │ ├── http_fault.proto │ ├── l4_fault.proto │ ├── proxy_mesh.proto │ └── route_rule.proto ├── snippets └── tools.MD └── test ├── README.md ├── config ├── conf.d │ ├── http.conf │ └── remote.conf └── nginx.conf ├── deploy.sh ├── iptable ├── prepare_proxy.sh └── tproxy.sh └── services └── http.js /.cargo/config: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nginxinc/ngx-istio-mixer/0e3dfaaf2fc38c7a013404965b993a8afa5cc6c4/.cargo/config -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | .idea 3 | .vscode 4 | nginx 5 | u1.* 6 | make.out 7 | grpc-rust 8 | ngx-rust -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "mixer-ngx", 4 | "mixer-transport", 5 | "mixer-tests" 6 | ] 7 | 8 | exclude = [ 9 | "build" 10 | ] 11 | 12 | 13 | [profile.release] 14 | lto = true 15 | 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2016 Nginx, Inc. 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | MODULE_NAME=ngx_http_istio_mixer_module 2 | MODULE_PROJ_NAME=ngx-http-istio-mixer 3 | NGX_DEBUG="--with-debug" 4 | VERSION=0.2.12-RC2 5 | REPO=ngx-istio-mixer 6 | USER=nginmesh 7 | 8 | 9 | include nginx.mk 10 | 11 | 12 | clean: 13 | cargo clean 14 | rm -f ${MIXER_CRATE}/src/grpc/attributes.rs 15 | rm -f ${MIXER_CRATE}/src/grpc/status.rs 16 | rm -f ${MIXER_CRATE}/src/grpc/check.rs 17 | rm -f ${MIXER_CRATE}/src/grpc/quota.rs 18 | rm -f ${MIXER_CRATE}/src/grpc/report.rs 19 | rm -f ${MIXER_CRATE}/src/grpc/service_grpc.rs 20 | rm -f module/*.so 21 | rm -rf dockercontext 22 | 23 | 24 | super_clean: clean 25 | rm -rf nginx/* 26 | 27 | 28 | report: 29 | cargo build --bin report_client 30 | 31 | test: 32 | cargo test -- --nocapture 33 | 34 | 35 | release: create_release upload_release 36 | 37 | create_release: 38 | github-release release \ 39 | --user ${USER} \ 40 | --repo ${REPO} \ 41 | --tag ${VERSION} \ 42 | --name "${VERSION}" \ 43 | --pre-release 44 | 45 | 46 | upload_release: 47 | github-release upload \ 48 | --user ${USER} \ 49 | --repo ${REPO} \ 50 | --tag ${VERSION} \ 51 | --name "${MODULE_NAME}.so" \ 52 | --file module/release/${MODULE_NAME}.so 53 | 54 | 55 | delete_release: 56 | github-release delete \ 57 | --user ${USER} \ 58 | --repo ${REPO} \ 59 | --tag ${VERSION} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Project Status: Abandoned – Initial development has started, but there has not yet been a stable, usable release; the project has been abandoned and the author(s) do not intend on continuing development.](https://www.repostatus.org/badges/latest/abandoned.svg)](https://www.repostatus.org/#abandoned) 2 | 3 | # NGINX dynamic module for Istio Mixer 4 | 5 | 6 | ## Dependencies 7 | 8 | Build system use Docker to generate the module binary. 9 | 10 | ## Compatibility 11 | 12 | * 1.11.x (last tested with 1.13.5) 13 | 14 | 15 | ## Synopsis 16 | 17 | ```nginx 18 | 19 | http { 20 | 21 | mixer_server istio-mixer.istio-system; 22 | mixer_port 9091; 23 | 24 | 25 | server { 26 | 27 | mixer_source_ip 10.0.0.0; 28 | mixer_source_uid kubernetes://productpage-v1-2213572757-758cs.beta1; 29 | mixer_source_service productpage.beta1.svc.cluster.local; 30 | mixer_destination_service abc.ns.svc.cluster.local; 31 | mixer_destination_uid details; 32 | 33 | 34 | location / { 35 | mixer_report on; 36 | proxy_pass http://service1; 37 | } 38 | 39 | 40 | 41 | } 42 | 43 | } 44 | 45 | ``` 46 | 47 | 48 | ## Directives 49 | 50 | ### mixer_server 51 | 52 | | - | - | 53 | | --- | --- | 54 | | **Syntax** | **mixer_server** | 55 | | **Default** | - | 56 | | **Context** | http | 57 | 58 | `Description:` Specify the mixer server address 59 | 60 | 61 | ### mixer_port 62 | 63 | | - | - | 64 | | --- | --- | 65 | | **Syntax** | **mixer_port** | 66 | | **Default** | - | 67 | | **Context** | http | 68 | 69 | `Description:` Specify the mixer server port 70 | 71 | 72 | ### mixer_source_ip 73 | 74 | | - | - | 75 | | --- | --- | 76 | | **Syntax** | **mixer_source_ip** | 77 | | **Default** | - | 78 | | **Context** | server, location | 79 | | **Mixer attribute** | source.ip | 80 | 81 | `Description:` Standard mixer attribute **Client IP address** 82 | 83 | ### mixer_source_uid 84 | 85 | | - | - | 86 | | --- | --- | 87 | | **Syntax** | **mixer_source_uid** | 88 | | **Default** | - | 89 | | **Context** | server, location | 90 | | **Mixer attribute** | source.uid | 91 | 92 | `Description:` Standard mixer attribute **Platform-specific unique identifier for the client instance of the source service** 93 | 94 | ### mixer_source_service 95 | 96 | | - | - | 97 | | --- | --- | 98 | | **Syntax** | **mixer_source_service** | 99 | | **Default** | - | 100 | | **Context** | server, location | 101 | | **Mixer attribute** | source.service | 102 | 103 | `Description:` Standard mixer attribute **The fully qualified name of the service that the client belongs to** 104 | 105 | 106 | ### mixer_source_port 107 | 108 | | - | - | 109 | | --- | --- | 110 | | **Syntax** | **mixer_source_port** | 111 | | **Default** | - | 112 | | **Context** | server, location | 113 | | **Mixer attribute** | source.service | 114 | 115 | `Description:` Standard mixer attribute **The fully qualified name of the service that the client belongs to** 116 | 117 | 118 | ### mixer_source_labels 119 | 120 | | - | - | 121 | | --- | --- | 122 | | **Syntax** | **mixer_source_labels** | 123 | | **Default** | - | 124 | | **Context** | server | 125 | | **Mixer attribute** | source.labels | 126 | 127 | `Description:` Standard mixer attribute **The map of key-value pairs attached to the client instance.** 128 | 129 | 130 | ### mixer_destination_service 131 | 132 | | - | - | 133 | | --- | --- | 134 | | **Syntax** | **mixer_destination_service** | 135 | | **Default** | - | 136 | | **Context** | server, location | 137 | | **Mixer attribute** | destination.servicee | 138 | 139 | `Description:` Standard mixer attribute **The fully qualified name of the service that the server belongs to** 140 | 141 | ### mixer_destination_uid 142 | 143 | | - | - | 144 | | --- | --- | 145 | | **Syntax** | **mixer_destination_service** | 146 | | **Default** | - | 147 | | **Context** | server, location | 148 | | **Mixer attribute** | destination.uid | 149 | 150 | `Description:` Standard mixer attribute **Platform-specific unique identifier for the server instance of the destination service.** 151 | 152 | 153 | ### mixer_destination_labels 154 | 155 | | - | - | 156 | | --- | --- | 157 | | **Syntax** | **mixer_destination_labels** | 158 | | **Default** | - | 159 | | **Context** | server | 160 | | **Mixer attribute** | destination.labels | 161 | 162 | `Description:` Standard mixer attribute **A map of key-value pairs attached to the server instance.** 163 | 164 | 165 | 166 | ## Installation 167 | 168 | 1. Clone the git repository 169 | 170 | ``` 171 | shell> git clone git@github.com:nginmesh/ngx-istio-mixer.git 172 | ``` 173 | 174 | 2. Build the dynamic module 175 | 176 | ``` 177 | shell> make build-base;make build-module 178 | ``` 179 | 180 | This copies the generated .so file into module/release directory 181 | 182 | 183 | 184 | ## Running unit test 185 | 186 | ```bash 187 | make test-unit 188 | ``` 189 | -------------------------------------------------------------------------------- /docker/.gitignore: -------------------------------------------------------------------------------- 1 | context 2 | -------------------------------------------------------------------------------- /docker/Dockerfile.base: -------------------------------------------------------------------------------- 1 | FROM nginmesh/ngx-rust-tool:1.21.0 2 | 3 | MAINTAINER Sehyo Chang "sehyo@nginx.com" 4 | 5 | RUN apt-get install -y pkg-config libssl-dev 6 | 7 | RUN mkdir /src 8 | ADD ./Makefile /src 9 | ADD ./nginx.mk /src 10 | RUN mkdir /src/build 11 | RUN mkdir /src/protobuf 12 | ADD ./protobuf /src/protobuf 13 | ADD ./module /src/module 14 | RUN cd /src;make nginx-setup; 15 | 16 | # add source for initial build to download dependency 17 | ADD ./Cargo.toml /src 18 | ADD ./Cargo.lock /src 19 | ADD ./mixer-ngx /src/mixer-ngx 20 | ADD ./mixer-transport /src/mixer-transport 21 | ADD ./mixer-tests /src/mixer-tests 22 | RUN cd /src;cargo build --all 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /docker/Dockerfile.build-alpine-nginx: -------------------------------------------------------------------------------- 1 | FROM mhart/alpine-node:9.0.0 2 | 3 | MAINTAINER Sehyo Chang "sehyo@nginx.com" 4 | 5 | # https://github.com/nginxinc/docker-nginx/blob/3ba04e37d8f9ed7709fd30bf4dc6c36554e578ac/mainline/alpine/Dockerfile 6 | 7 | 8 | 9 | LABEL maintainer="NGINX Docker Maintainers " 10 | 11 | ENV NGINX_VERSION 1.13.6 12 | 13 | RUN GPG_KEYS=B0F4253373F8F6F510D42178520A9993A1C052F8 \ 14 | && CONFIG="\ 15 | --prefix=/etc/nginx \ 16 | --sbin-path=/usr/sbin/nginx \ 17 | --modules-path=/usr/lib/nginx/modules \ 18 | --conf-path=/etc/nginx/nginx.conf \ 19 | --error-log-path=/var/log/nginx/error.log \ 20 | --http-log-path=/var/log/nginx/access.log \ 21 | --pid-path=/var/run/nginx.pid \ 22 | --lock-path=/var/run/nginx.lock \ 23 | --http-client-body-temp-path=/var/cache/nginx/client_temp \ 24 | --http-proxy-temp-path=/var/cache/nginx/proxy_temp \ 25 | --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \ 26 | --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \ 27 | --http-scgi-temp-path=/var/cache/nginx/scgi_temp \ 28 | --user=nginx \ 29 | --group=nginx \ 30 | --with-http_ssl_module \ 31 | --with-http_realip_module \ 32 | --with-http_addition_module \ 33 | --with-http_sub_module \ 34 | --with-http_dav_module \ 35 | --with-http_flv_module \ 36 | --with-http_mp4_module \ 37 | --with-http_gunzip_module \ 38 | --with-http_gzip_static_module \ 39 | --with-http_random_index_module \ 40 | --with-http_secure_link_module \ 41 | --with-http_stub_status_module \ 42 | --with-http_auth_request_module \ 43 | --with-http_xslt_module=dynamic \ 44 | --with-http_image_filter_module=dynamic \ 45 | --with-http_geoip_module=dynamic \ 46 | --with-threads \ 47 | --with-stream \ 48 | --with-stream_ssl_module \ 49 | --with-stream_ssl_preread_module \ 50 | --with-stream_realip_module \ 51 | --with-stream_geoip_module=dynamic \ 52 | --with-http_slice_module \ 53 | --with-mail \ 54 | --with-mail_ssl_module \ 55 | --with-compat \ 56 | --with-file-aio \ 57 | --with-http_v2_module \ 58 | " \ 59 | && addgroup -S nginx \ 60 | && adduser -D -S -h /var/cache/nginx -s /sbin/nologin -G nginx nginx \ 61 | && apk add --no-cache --virtual .build-deps \ 62 | gcc \ 63 | libc-dev \ 64 | make \ 65 | openssl-dev \ 66 | pcre-dev \ 67 | zlib-dev \ 68 | linux-headers \ 69 | curl \ 70 | gnupg \ 71 | libxslt-dev \ 72 | gd-dev \ 73 | geoip-dev \ 74 | && curl -fSL http://nginx.org/download/nginx-$NGINX_VERSION.tar.gz -o nginx.tar.gz \ 75 | && curl -fSL http://nginx.org/download/nginx-$NGINX_VERSION.tar.gz.asc -o nginx.tar.gz.asc \ 76 | && export GNUPGHOME="$(mktemp -d)" \ 77 | && found=''; \ 78 | for server in \ 79 | ha.pool.sks-keyservers.net \ 80 | hkp://keyserver.ubuntu.com:80 \ 81 | hkp://p80.pool.sks-keyservers.net:80 \ 82 | pgp.mit.edu \ 83 | ; do \ 84 | echo "Fetching GPG key $GPG_KEYS from $server"; \ 85 | gpg --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$GPG_KEYS" && found=yes && break; \ 86 | done; \ 87 | test -z "$found" && echo >&2 "error: failed to fetch GPG key $GPG_KEYS" && exit 1; \ 88 | gpg --batch --verify nginx.tar.gz.asc nginx.tar.gz \ 89 | && rm -r "$GNUPGHOME" nginx.tar.gz.asc \ 90 | && mkdir -p /usr/src \ 91 | && tar -zxC /usr/src -f nginx.tar.gz \ 92 | && rm nginx.tar.gz \ 93 | && cd /usr/src/nginx-$NGINX_VERSION \ 94 | && find . -type f -exec sed -i 's/IPPROTO_IP/SOL_IP/g' {} + \ 95 | && ./configure $CONFIG --with-debug \ 96 | && make -j$(getconf _NPROCESSORS_ONLN) \ 97 | && mv objs/nginx objs/nginx-debug \ 98 | && mv objs/ngx_http_xslt_filter_module.so objs/ngx_http_xslt_filter_module-debug.so \ 99 | && mv objs/ngx_http_image_filter_module.so objs/ngx_http_image_filter_module-debug.so \ 100 | && mv objs/ngx_http_geoip_module.so objs/ngx_http_geoip_module-debug.so \ 101 | && mv objs/ngx_stream_geoip_module.so objs/ngx_stream_geoip_module-debug.so \ 102 | && ./configure $CONFIG \ 103 | && make -j$(getconf _NPROCESSORS_ONLN) \ 104 | && make install \ 105 | && rm -rf /etc/nginx/html/ \ 106 | && mkdir /etc/nginx/conf.d/ \ 107 | && mkdir -p /usr/share/nginx/html/ \ 108 | && install -m644 html/index.html /usr/share/nginx/html/ \ 109 | && install -m644 html/50x.html /usr/share/nginx/html/ \ 110 | && install -m755 objs/nginx-debug /usr/sbin/nginx-debug \ 111 | && install -m755 objs/ngx_http_xslt_filter_module-debug.so /usr/lib/nginx/modules/ngx_http_xslt_filter_module-debug.so \ 112 | && install -m755 objs/ngx_http_image_filter_module-debug.so /usr/lib/nginx/modules/ngx_http_image_filter_module-debug.so \ 113 | && install -m755 objs/ngx_http_geoip_module-debug.so /usr/lib/nginx/modules/ngx_http_geoip_module-debug.so \ 114 | && install -m755 objs/ngx_stream_geoip_module-debug.so /usr/lib/nginx/modules/ngx_stream_geoip_module-debug.so \ 115 | && ln -s ../../usr/lib/nginx/modules /etc/nginx/modules \ 116 | && strip /usr/sbin/nginx* \ 117 | && strip /usr/lib/nginx/modules/*.so \ 118 | # && rm -rf /usr/src/nginx-$NGINX_VERSION \ 119 | \ 120 | # Bring in gettext so we can get `envsubst`, then throw 121 | # the rest away. To do this, we need to install `gettext` 122 | # then move `envsubst` out of the way so `gettext` can 123 | # be deleted completely, then move `envsubst` back. 124 | && apk add --no-cache --virtual .gettext gettext \ 125 | && mv /usr/bin/envsubst /tmp/ \ 126 | \ 127 | && runDeps="$( \ 128 | scanelf --needed --nobanner --format '%n#p' /usr/sbin/nginx /usr/lib/nginx/modules/*.so /tmp/envsubst \ 129 | | tr ',' '\n' \ 130 | | sort -u \ 131 | | awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \ 132 | )" \ 133 | && apk add --no-cache --virtual .nginx-rundeps $runDeps \ 134 | && apk del .build-deps \ 135 | && apk del .gettext \ 136 | && mv /tmp/envsubst /usr/local/bin/ \ 137 | \ 138 | # forward request and error logs to docker log collector 139 | && ln -sf /dev/stdout /var/log/nginx/access.log \ 140 | && ln -sf /dev/stderr /var/log/nginx/error.log 141 | 142 | COPY build/nginx/nginx.conf /etc/nginx/nginx.conf 143 | COPY build/nginx/default.conf /etc/nginx/conf.d/default.conf 144 | 145 | RUN apk update 146 | 147 | # install dev en 148 | RUN apk add curl wget unzip gnupg vim 149 | RUN apk add netcat-openbsd make net-tools iptables procps 150 | RUN apk add iproute2 libc6-compat 151 | 152 | 153 | EXPOSE 80 154 | 155 | STOPSIGNAL SIGTERM 156 | 157 | CMD ["nginx", "-g", "daemon off;"] 158 | 159 | 160 | -------------------------------------------------------------------------------- /docker/Dockerfile.module: -------------------------------------------------------------------------------- 1 | FROM nginmesh/ngx_http_istio_mixer_module-base:latest 2 | 3 | MAINTAINER Sehyo Chang "sehyo@nginx.com" 4 | 5 | # this is coming from context which is from /build/context not root of the source 6 | ADD ./mixer-ngx /src/mixer-ngx 7 | ADD ./mixer-transport /src/mixer-transport 8 | ADD ./mixer-tests /src/mixer-tests 9 | ADD ./module /src/module 10 | RUN cd /src;make nginx-module -------------------------------------------------------------------------------- /mixer-ngx/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ngx-mixer-module" 3 | version = "0.1.1" 4 | authors = ["Sehyo Chang sehyo@nginx.com"] 5 | 6 | 7 | 8 | [lib] 9 | doctest = false 10 | test = true 11 | crate-type = ["staticlib","rlib"] 12 | 13 | 14 | 15 | [dependencies] 16 | grpc = "0.2.1" 17 | protobuf = "1.4.1" 18 | futures = "0.1.14" 19 | futures-cpupool = "0.1.5" 20 | tls-api = "0.1.8" 21 | httpbis = "0.4.1" 22 | lazy_static = "0.2.8" 23 | time = "0.1.38" 24 | base64 = "0.6.0" 25 | ngx-rust = { git = "https://github.com/nginmesh/ngx-rust.git", version = "0.1.2" } 26 | ngx-mixer-transport = { path = "../mixer-transport" , version = "0.0.27" } 27 | -------------------------------------------------------------------------------- /mixer-ngx/snippets/tools.MD: -------------------------------------------------------------------------------- 1 | # List of handy scripts to work with nginmesh/istio 2 | 3 | 4 | ## Find mixer pod in the istio-system namespace 5 | ```bash 6 | kubectl get pod -l istio=mixer -n istio-system -o jsonpath='{.items[0].metadata.name}' 7 | ``` 8 | 9 | ## Logs from mixer pod 10 | ```bash 11 | kubectl logs -f $(kubectl get pod -l istio=mixer -n istio-system -o jsonpath='{.items[0].metadata.name}') -n istio-system -c mixer 12 | ``` 13 | 14 | ## mixer address 15 | ``` 16 | istio-mixer.istio-system:9093 17 | ``` 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /mixer-ngx/src/.gitignore: -------------------------------------------------------------------------------- 1 | naj -------------------------------------------------------------------------------- /mixer-ngx/src/encode.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use base64::{encode, decode}; 3 | use std::str; 4 | use std::vec::Vec; 5 | 6 | /** 7 | * convert istio headers into a single string that can be sent as http header 8 | */ 9 | #[allow(dead_code)] 10 | pub fn encode_istio_header(headers: &Vec<(&str,&str)>) -> String { 11 | 12 | // for now we do simple serialize, we can convert to same format as envoy for version 0.2 with new mixer API 13 | 14 | let mut out = String::from(""); 15 | 16 | for &(key, value ) in headers { 17 | out.push_str(key); 18 | out.push_str("@"); 19 | out.push_str(value); 20 | out.push_str("!"); 21 | } 22 | 23 | return encode(&out); 24 | } 25 | 26 | // decode istio header and convert to map 27 | #[allow(dead_code)] 28 | pub fn decode_istio_header(encoded_string: &str) -> HashMap { 29 | 30 | let decode_bytes = &decode(encoded_string).unwrap()[..]; 31 | let decode_value = str::from_utf8(decode_bytes).unwrap(); 32 | 33 | 34 | let mut out = HashMap::new(); 35 | 36 | let attrs_list = decode_value.split("!"); 37 | 38 | for attr in attrs_list { 39 | let tokens = attr.split("@").collect::>(); 40 | if tokens.len() == 2 { 41 | out.insert(String::from(tokens[0]),String::from(tokens[1])); 42 | } 43 | } 44 | 45 | return out; 46 | 47 | 48 | 49 | } -------------------------------------------------------------------------------- /mixer-ngx/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate time; 2 | extern crate base64; 3 | extern crate grpc; 4 | extern crate futures; 5 | extern crate protobuf; 6 | 7 | #[macro_use] 8 | extern crate ngx_rust; 9 | 10 | extern crate ngx_mixer_transport; 11 | 12 | #[macro_use] 13 | extern crate lazy_static; 14 | 15 | 16 | 17 | pub mod ngx; 18 | 19 | pub mod message; 20 | pub mod mixer_report; 21 | pub mod mixer_check; 22 | pub mod mixer_thread; 23 | 24 | pub use mixer_thread::nginmesh_mixer_init; 25 | pub use mixer_thread::nginmesh_mixer_exit; 26 | pub use mixer_check::nginmesh_mixer_check_handler; 27 | pub use mixer_report::nginmesh_mixer_report_handler; 28 | -------------------------------------------------------------------------------- /mixer-ngx/src/message.rs: -------------------------------------------------------------------------------- 1 | use std::sync::mpsc::{ Sender,Receiver}; 2 | use std::sync::Mutex; 3 | 4 | 5 | use ngx_mixer_transport::mixer_grpc::attributes::CompressedAttributes; 6 | 7 | // Struct used to send and receive data from mixer hub 8 | // Channels utilize mutexes so that communication can be 9 | // Restricted to a single item at one time. 10 | pub struct Channels { 11 | pub tx: Mutex>, 12 | pub rx: Mutex> 13 | } 14 | 15 | // Struct to hold mixer hub server and ports, as well as 16 | // information to send 17 | #[derive(Clone, Debug)] 18 | pub struct MixerInfo { 19 | pub server_name: String, 20 | pub server_port: u16, 21 | pub attributes: CompressedAttributes 22 | } 23 | 24 | 25 | -------------------------------------------------------------------------------- /mixer-ngx/src/mixer_check.rs: -------------------------------------------------------------------------------- 1 | use futures::future::Future; 2 | 3 | 4 | use ngx_rust::bindings::ngx_http_request_s; 5 | use ngx_rust::bindings::ngx_int_t; 6 | use ngx_rust::bindings::{ NGX_OK, NGX_HTTP_UNAUTHORIZED }; 7 | 8 | 9 | use ngx::server_config::ngx_http_mixer_srv_conf_t; 10 | use ngx::main_config::ngx_http_mixer_main_conf_t; 11 | 12 | 13 | use ngx_mixer_transport::attribute::attr_wrapper::AttributeWrapper; 14 | use ngx_mixer_transport::transport::status:: { StatusCodeEnum }; 15 | 16 | use ngx_mixer_transport::istio_client::mixer_client_wrapper::MixerClientWrapper ; 17 | use ngx_mixer_transport::transport::mixer_grpc::GrpcTransport; 18 | use ngx_mixer_transport::transport::server_info::MixerInfo; 19 | 20 | use ngx::config::MixerConfig; 21 | 22 | 23 | lazy_static! { 24 | static ref DEFAULT_MIXER_CLIENT: MixerClientWrapper = MixerClientWrapper::new(); 25 | } 26 | 27 | 28 | 29 | 30 | // perform check 31 | pub fn check(request: &ngx_http_request_s,server_name: &str,server_port: u16, attr: AttributeWrapper) -> bool { 32 | 33 | 34 | let info = MixerInfo { server_name: String::from(server_name), server_port: server_port}; 35 | 36 | let transport = GrpcTransport::new(info,attr); 37 | let result = DEFAULT_MIXER_CLIENT.check(transport).wait(); 38 | 39 | match result { 40 | Ok(_) => return true, 41 | Err(error) => { 42 | ngx_http_debug!(request,"rust check transport failed: {:?}", error); 43 | 44 | if error.get_error_code() == StatusCodeEnum::PERMISSION_DENIED { 45 | return false; 46 | } 47 | } 48 | } 49 | 50 | true 51 | 52 | } 53 | 54 | 55 | #[no_mangle] 56 | pub extern fn nginmesh_mixer_check_handler(request: &ngx_http_request_s, 57 | main_config: &ngx_http_mixer_main_conf_t, 58 | srv_conf_option: Option<&ngx_http_mixer_srv_conf_t>) -> ngx_int_t { 59 | 60 | ngx_http_debug!(request,"mixer check handler called"); 61 | 62 | let mut attributes = AttributeWrapper::new(); 63 | 64 | if let Some(srv_conf) = srv_conf_option { 65 | ngx_http_debug!(request,"calling mixer server to validate check"); 66 | srv_conf.process_istio_attr(&mut attributes); 67 | } 68 | request.process_istio_attr(&mut attributes); 69 | 70 | 71 | let server_name = main_config.mixer_server.to_str(); 72 | let server_port = main_config.mixer_port as u16; 73 | 74 | 75 | if !check(request,server_name,server_port, attributes) { 76 | ngx_http_debug!(request,"mixer check denied"); 77 | return NGX_HTTP_UNAUTHORIZED as ngx_int_t; 78 | } 79 | 80 | ngx_http_debug!(request,"mixer check allowed"); 81 | return NGX_OK as ngx_int_t; 82 | 83 | } 84 | -------------------------------------------------------------------------------- /mixer-ngx/src/mixer_report.rs: -------------------------------------------------------------------------------- 1 | // use std::str; 2 | use std::sync::mpsc::{channel}; 3 | use std::sync::Mutex; 4 | 5 | use grpc::RequestOptions; 6 | use ngx_mixer_transport::mixer_grpc::service_grpc::MixerClient; 7 | use ngx_mixer_transport::mixer_grpc::report::ReportRequest; 8 | use ngx_mixer_transport::mixer_grpc::attributes::CompressedAttributes; 9 | use ngx_mixer_transport::mixer_grpc::service_grpc::Mixer; 10 | 11 | 12 | use protobuf::RepeatedField; 13 | use ngx_rust::bindings:: { ngx_array_t }; 14 | use ngx_rust::bindings::ngx_http_request_s; 15 | use ngx_rust::bindings::ngx_http_upstream_state_t; 16 | 17 | use ngx_mixer_transport::attribute::attr_wrapper::AttributeWrapper; 18 | use ngx_mixer_transport::attribute::global_dict::GlobalDictionary; 19 | use ngx_mixer_transport::attribute::message_dict::MessageDictionary; 20 | use ngx_mixer_transport::attribute::global_dict::{ RESPONSE_DURATION, CONTEXT_PROTOCOL }; 21 | 22 | 23 | use super::message::Channels; 24 | use super::message::MixerInfo; 25 | 26 | use ngx::main_config::ngx_http_mixer_main_conf_t; 27 | use ngx::server_config::ngx_http_mixer_srv_conf_t; 28 | use ngx::config::MixerConfig; 29 | 30 | 31 | // initialize channel that can be shared 32 | lazy_static! { 33 | static ref CHANNELS: Channels = { 34 | let (tx, rx) = channel(); 35 | 36 | Channels { 37 | tx: Mutex::new(tx), 38 | rx: Mutex::new(rx), 39 | } 40 | }; 41 | } 42 | 43 | // background activy for report. 44 | // receives report attributes and send out to mixer 45 | // Spawned by nginx module init function, spawns new 46 | // thread to listen for mixer attributes 47 | pub fn mixer_report_background() { 48 | 49 | let rx = CHANNELS.rx.lock().unwrap(); 50 | 51 | loop { 52 | ngx_event_debug!("mixer report thread waiting"); 53 | // Receive attributes from background thread 54 | let info = rx.recv().unwrap(); 55 | ngx_event_debug!("mixer report thread woke up"); 56 | 57 | ngx_event_debug!("New Mixer Request, server: {} port: {}", info.server_name, info.server_port); 58 | let client = MixerClient::new_plain( &info.server_name, info.server_port , Default::default()).expect("init"); 59 | 60 | let mut req = ReportRequest::new(); 61 | let mut rf = RepeatedField::default(); 62 | rf.push(info.attributes); 63 | req.set_attributes(rf); 64 | 65 | let resp = client.report(RequestOptions::new(), req); 66 | 67 | let result = resp.wait(); 68 | 69 | ngx_event_debug!("mixer report thread: finished sending to mixer, {:?}",result); 70 | } 71 | } 72 | 73 | 74 | // send to background thread using channels 75 | #[allow(unused_must_use)] 76 | fn send_dispatcher(request: &ngx_http_request_s,main_config: &ngx_http_mixer_main_conf_t, attr: CompressedAttributes) { 77 | 78 | // Get mixer server and port from main config (Defined in c module) 79 | let server_name = main_config.mixer_server.to_str(); 80 | let server_port = main_config.mixer_port as u16; 81 | 82 | 83 | let tx = CHANNELS.tx.lock().unwrap().clone(); 84 | let info = MixerInfo { server_name: String::from(server_name), server_port: server_port, attributes: attr}; 85 | 86 | 87 | // Send information to background thread 88 | tx.send(info.clone()); 89 | 90 | // NGINX debug logging 91 | ngx_http_debug!(request,"send attribute to mixer report background task"); 92 | 93 | } 94 | 95 | 96 | // Total Upstream response Time Calculation Function Start 97 | 98 | fn upstream_response_time_calculation( upstream_states: *const ngx_array_t ) -> i64 { 99 | 100 | unsafe { 101 | // Get request information array 102 | let upstream_value = *upstream_states; 103 | // Hold array of elements 104 | let upstream_response_time_list = upstream_value.elts; 105 | // Number of elements 106 | let upstream_response_time_n = upstream_value.nelts as isize; 107 | // Size of a single element. Used to index array 108 | let upstream_response_time_size = upstream_value.size as isize; 109 | // Variable going to be used to hold the extracted total response time from array 110 | let mut upstream_response_time_total:i64 = 0; 111 | 112 | // For loop to iterate through number of elements in upstream_response and count total response time 113 | for i in 0..upstream_response_time_n as isize { 114 | 115 | // Response time pointer gets index i * size of each element. 116 | let upstream_response_time_ptr = upstream_response_time_list.offset(i*upstream_response_time_size) as *mut ngx_http_upstream_state_t; 117 | // Get response time of upstream 118 | let upstream_response_time_value = (*upstream_response_time_ptr).response_time as i64; 119 | // Tally total response time 120 | upstream_response_time_total = upstream_response_time_total + upstream_response_time_value; 121 | 122 | } 123 | 124 | return upstream_response_time_total; 125 | } 126 | } 127 | 128 | 129 | #[no_mangle] 130 | pub extern fn nginmesh_mixer_report_handler(request: &ngx_http_request_s,main_config: &ngx_http_mixer_main_conf_t, 131 | srv_conf: &ngx_http_mixer_srv_conf_t) { 132 | 133 | // Calls debug logging through NGINX - macro set up in ngx-rust/log.rs 134 | ngx_http_debug!(request,"invoking nginx report"); 135 | 136 | // Create new HashMap - mixer-transport/attribute/attr_wrapper.rs 137 | let mut attr = AttributeWrapper::new(); 138 | 139 | // Ngx_http_mixer_srv_conf_t made compatible through struct definition in ./ngx/server_config.rs 140 | srv_conf.process_istio_attr(&mut attr); 141 | 142 | ngx_event_debug!("Mixer Attributes: {:?}", attr); 143 | // Send request attribute to mixer 144 | request.process_istio_attr(&mut attr); 145 | 146 | // Get total response time of all upstreams 147 | attr.insert_int64_attribute(RESPONSE_DURATION, upstream_response_time_calculation(request.upstream_states)); 148 | 149 | // Access response headers 150 | let headers_out = &request.headers_out; 151 | // Process output headers 152 | headers_out.process_istio_attr(&mut attr); 153 | 154 | // Create new message dictionary 155 | let mut message_dict = MessageDictionary::new(GlobalDictionary::new()); 156 | 157 | ngx_http_debug!(request,"setting mixer attributes"); 158 | 159 | attr.insert_string_attribute( CONTEXT_PROTOCOL, "http"); 160 | 161 | // Send attributes from config to background thread 162 | send_dispatcher(request,main_config, attr.as_attributes(&mut message_dict)); 163 | 164 | } 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /mixer-ngx/src/mixer_thread.rs: -------------------------------------------------------------------------------- 1 | 2 | 3 | use std::thread ; 4 | 5 | use ngx_rust::bindings::ngx_int_t; 6 | use ngx_rust::bindings::NGX_OK; 7 | 8 | use mixer_report::mixer_report_background; 9 | 10 | 11 | 12 | // start background activities 13 | #[no_mangle] 14 | pub extern fn nginmesh_mixer_init() -> ngx_int_t { 15 | 16 | ngx_event_debug!("init mixer start "); 17 | // Spawn new thread to listen for mixer attributes from NGINX and send to mixer 18 | thread::spawn(|| { 19 | ngx_event_debug!("starting mixer report background task"); 20 | mixer_report_background(); 21 | }); 22 | 23 | 24 | ngx_event_debug!("init mixer end "); 25 | return NGX_OK as ngx_int_t; 26 | } 27 | 28 | #[no_mangle] 29 | pub extern fn nginmesh_mixer_exit() { 30 | 31 | ngx_event_debug!("mixer exit "); 32 | } 33 | 34 | -------------------------------------------------------------------------------- /mixer-ngx/src/ngx/config.rs: -------------------------------------------------------------------------------- 1 | 2 | use ngx_mixer_transport::attribute::attr_wrapper::AttributeWrapper; 3 | 4 | pub trait MixerConfig { 5 | 6 | // convert and migrate values to istio attributes 7 | fn process_istio_attr(&self, attr: &mut AttributeWrapper); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /mixer-ngx/src/ngx/location_config.rs: -------------------------------------------------------------------------------- 1 | extern crate ngx_rust; 2 | 3 | use ngx_rust::bindings:: { ngx_str_t, ngx_flag_t } ; 4 | use ngx_mixer_transport::attribute::attr_wrapper::AttributeWrapper; 5 | use ngx_mixer_transport::attribute::global_dict::{ DESTINATION_SERVICE }; 6 | 7 | use ngx::config::MixerConfig; 8 | 9 | #[repr(C)] 10 | pub struct ngx_http_mixer_loc_conf_t { 11 | pub enable_report: ngx_flag_t, // for every location, we need flag to enable/disable mixer 12 | pub enable_check: ngx_flag_t, 13 | pub destination_service: ngx_str_t 14 | } 15 | 16 | impl MixerConfig for ngx_http_mixer_loc_conf_t { 17 | 18 | 19 | fn process_istio_attr(&self,attr: &mut AttributeWrapper) { 20 | 21 | attr.insert_string_attribute( DESTINATION_SERVICE,self.destination_service.to_str()); 22 | 23 | } 24 | 25 | 26 | } 27 | 28 | 29 | -------------------------------------------------------------------------------- /mixer-ngx/src/ngx/main_config.rs: -------------------------------------------------------------------------------- 1 | extern crate ngx_rust; 2 | 3 | use ngx_rust::bindings:: { ngx_int_t, ngx_str_t } ; 4 | 5 | 6 | #[repr(C)] 7 | pub struct ngx_http_mixer_main_conf_t { 8 | 9 | pub mixer_server: ngx_str_t, 10 | pub mixer_port: ngx_int_t 11 | } 12 | 13 | 14 | -------------------------------------------------------------------------------- /mixer-ngx/src/ngx/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod location_config; 2 | pub mod request; 3 | pub mod main_config; 4 | pub mod server_config; 5 | pub mod config; 6 | 7 | -------------------------------------------------------------------------------- /mixer-ngx/src/ngx/request.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::collections::HashMap; 3 | use protobuf::well_known_types::Timestamp; 4 | use ngx_rust::bindings:: { ngx_http_request_s, ngx_http_headers_out_t} ; 5 | use ngx_mixer_transport::attribute::attr_wrapper::AttributeWrapper; 6 | use ngx_mixer_transport::attribute::global_dict::{ REQUEST_HEADER, REQUEST_HOST, REQUEST_METHOD, REQUEST_PATH, 7 | REQUEST_REFER, REQUEST_SCHEME, REQUEST_SIZE, REQUEST_TIME, REQUEST_USERAGENT, 8 | SOURCE_UID, SRC_UID_HEADER, RESPONSE_CODE, RESPONSE_SIZE, RESPONSE_HEADERS 9 | }; 10 | 11 | use super::config::MixerConfig; 12 | 13 | 14 | impl MixerConfig for ngx_http_request_s { 15 | 16 | 17 | 18 | fn process_istio_attr(&self, attr: &mut AttributeWrapper ) { 19 | 20 | ngx_http_debug!(self,"send request attribute to mixer"); 21 | 22 | let headers_in = self.headers_in; 23 | 24 | 25 | attr.insert_string_attribute(REQUEST_HOST, headers_in.host_str()); 26 | attr.insert_string_attribute(REQUEST_METHOD, self.method_name.to_str()); 27 | attr.insert_string_attribute(REQUEST_PATH, self.uri.to_str()); 28 | 29 | let referer = headers_in.referer_str(); 30 | if let Some(ref_str) = referer { 31 | attr.insert_string_attribute(REQUEST_REFER, ref_str); 32 | } 33 | 34 | //let scheme = request.http_protocol.to_str(); 35 | attr.insert_string_attribute(REQUEST_SCHEME, "http"); // hard code now 36 | 37 | 38 | attr.insert_int64_attribute(REQUEST_SIZE, self.request_length); 39 | 40 | let mut request_time = Timestamp::new(); 41 | request_time.set_seconds(self.start_sec); 42 | request_time.set_nanos(self.start_msec as i32); 43 | attr.insert_time_stamp_attribute(REQUEST_TIME, request_time); 44 | 45 | attr.insert_string_attribute(REQUEST_USERAGENT, headers_in.user_agent_str()); 46 | 47 | 48 | // fill in the string value 49 | let mut map: HashMap = HashMap::new(); 50 | { 51 | for (name,value) in headers_in.headers_iterator() { 52 | ngx_http_debug!(self,"in header name: {}, value: {}",&name,&value); 53 | 54 | match name.as_ref() { 55 | 56 | SRC_UID_HEADER => { 57 | ngx_http_debug!(self,"source UID received {}",&value); 58 | attr.insert_string_attribute( SOURCE_UID,&value); 59 | }, 60 | _ => { 61 | ngx_http_debug!(self,"other source header {}",&name); 62 | map.insert(name,value); 63 | } 64 | } 65 | 66 | 67 | } 68 | } 69 | 70 | attr.insert_string_map(REQUEST_HEADER, map); 71 | 72 | } 73 | } 74 | 75 | 76 | 77 | impl MixerConfig for ngx_http_headers_out_t { 78 | 79 | fn process_istio_attr(&self, attr: &mut AttributeWrapper, ) { 80 | 81 | 82 | // ngx_http_debug!("send request header attribute to mixer"); 83 | // Add response code and response size from request 84 | attr.insert_int64_attribute(RESPONSE_CODE, self.status as i64); 85 | attr.insert_int64_attribute(RESPONSE_SIZE, self.content_length_n); 86 | 87 | // fill in the string value from all values of request struct 88 | let mut map: HashMap = HashMap::new(); 89 | { 90 | for (name,value) in self.headers_iterator() { 91 | 92 | map.insert(name,value); 93 | 94 | } 95 | } 96 | // Add response headers 97 | attr.insert_string_map(RESPONSE_HEADERS, map); 98 | } 99 | } 100 | 101 | 102 | -------------------------------------------------------------------------------- /mixer-ngx/src/ngx/server_config.rs: -------------------------------------------------------------------------------- 1 | extern crate ngx_rust; 2 | 3 | use std::collections::HashMap; 4 | use ngx_rust::bindings:: { ngx_uint_t, ngx_str_t, ngx_array_t } ; 5 | 6 | use ngx_mixer_transport::attribute::attr_wrapper::AttributeWrapper; 7 | use ngx_mixer_transport::attribute::global_dict::{ SOURCE_IP, SOURCE_UID, SOURCE_SERVICE, SOURCE_PORT, 8 | SOURCE_LABELS, DESTINATION_SERVICE, DESTINATION_IP, DESTINATION_UID, DESTINATION_LABELS 9 | }; 10 | 11 | use super::config::MixerConfig; 12 | use std::net::Ipv4Addr; 13 | 14 | #[repr(C)] 15 | pub struct service_labels { 16 | pub key: *const ngx_array_t, 17 | pub value: *const ngx_array_t 18 | 19 | } 20 | 21 | // ngx_http_mixer_srv_conf_t struct made compatible with data type in c module using #[repr(C)] 22 | #[repr(C)] 23 | pub struct ngx_http_mixer_srv_conf_t { 24 | 25 | pub destination_service: ngx_str_t, 26 | pub destination_uid: ngx_str_t, 27 | pub destination_ip: ngx_str_t, 28 | pub destination_labels: service_labels, 29 | pub source_ip: ngx_str_t, 30 | pub source_uid: ngx_str_t, 31 | pub source_service: ngx_str_t, 32 | pub source_port: ngx_uint_t, 33 | pub source_labels: service_labels 34 | } 35 | 36 | impl MixerConfig for ngx_http_mixer_srv_conf_t { 37 | 38 | fn process_istio_attr(&self, attr: &mut AttributeWrapper) { 39 | ngx_event_debug!("Processing server attributes"); 40 | 41 | let dest_ip = self.destination_ip.to_str(); 42 | let source_ip = self.source_ip.to_str(); 43 | if dest_ip.len() != 0 { 44 | attr.insert_ip_attribute( DESTINATION_IP, dest_ip.parse::().unwrap()); 45 | } 46 | if source_ip.len() != 0 { 47 | attr.insert_ip_attribute( SOURCE_IP, source_ip.parse::().unwrap()); 48 | } 49 | 50 | attr.insert_string_attribute( DESTINATION_SERVICE, self.destination_service.to_str()); 51 | attr.insert_string_attribute( DESTINATION_UID, self.destination_uid.to_str()); 52 | attr.insert_string_map( DESTINATION_LABELS, self.destination_labels.to_map()); 53 | attr.insert_string_attribute( SOURCE_UID,self.source_uid.to_str()); 54 | attr.insert_string_attribute( SOURCE_SERVICE,self.source_service.to_str()); 55 | attr.insert_int64_attribute( SOURCE_PORT,self.source_port as i64); 56 | attr.insert_string_map( SOURCE_LABELS, self.source_labels.to_map()); 57 | } 58 | } 59 | 60 | impl service_labels { 61 | 62 | fn to_map(&self) -> HashMap { 63 | 64 | let mut out_map: HashMap = HashMap::new(); 65 | 66 | if (self.key as *const u8).is_null() { 67 | return out_map; 68 | } else { 69 | for (key,value) in self.iter() { 70 | out_map.insert(key, value); 71 | } 72 | } 73 | 74 | return out_map; 75 | } 76 | 77 | pub fn iter(&self) -> LabelsIterator { 78 | 79 | unsafe { 80 | LabelsIterator { 81 | key: (*self.key).elts as *const ngx_str_t, 82 | value: (*self.value).elts as *const ngx_str_t, 83 | nelts: (*self.key).nelts, 84 | i: 0 85 | } 86 | } 87 | 88 | } 89 | } 90 | 91 | pub struct LabelsIterator { 92 | key: *const ngx_str_t, 93 | value: *const ngx_str_t, 94 | nelts: ngx_uint_t, 95 | i: isize 96 | } 97 | 98 | impl Iterator for LabelsIterator { 99 | 100 | type Item = (String,String); 101 | 102 | fn next(&mut self) -> Option { 103 | 104 | unsafe { 105 | if (self.key as *const u8).is_null() 106 | || self.i >= self.nelts as isize { 107 | return None; 108 | } else { 109 | self.i = self.i + 1; 110 | 111 | return Some ( ((*self.key.offset(self.i - 1)).to_string(), (*self.value.offset(self.i - 1)).to_string()) ); 112 | } 113 | 114 | } 115 | } 116 | 117 | } 118 | 119 | 120 | -------------------------------------------------------------------------------- /mixer-tests/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ngx-mixer-test" 3 | version = "0.0.27" 4 | authors = ["Sehyo Chang sehyo@nginx.com"] 5 | 6 | [lib] 7 | doctest = false 8 | test = false 9 | 10 | 11 | 12 | [dependencies] 13 | reqwest = "0.8.0" 14 | hyper = "0.11.6" -------------------------------------------------------------------------------- /mixer-tests/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate reqwest; 2 | 3 | pub mod util; 4 | -------------------------------------------------------------------------------- /mixer-tests/src/util.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | use std::process::Output; 3 | use std::env; 4 | use std::io::Result; 5 | 6 | 7 | // perform make with argument 8 | pub fn make(arg: &str) -> Result { 9 | let current_path = env::current_dir().unwrap(); 10 | let make_path = current_path.parent().unwrap(); 11 | let path_name = format!("{}",make_path.display()); 12 | println!("executing make command at {}",path_name); 13 | let result = Command::new("/usr/bin/make") 14 | .args(&[arg]) 15 | .current_dir(path_name) 16 | .output(); 17 | 18 | match result { 19 | Err(e) => { 20 | println!("make error: {}", e); 21 | return Err(e); 22 | }, 23 | 24 | Ok(output) => { 25 | println!("status: {}", output.status); 26 | println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); 27 | println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); 28 | return Ok(output); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /mixer-tests/tests/nginx_check_test.rs: -------------------------------------------------------------------------------- 1 | extern crate reqwest; 2 | extern crate ngx_mixer_test; 3 | #[macro_use] 4 | extern crate hyper; 5 | 6 | use ngx_mixer_test::util::make; 7 | use std::io::Read; 8 | use hyper::header::Headers; 9 | use reqwest::StatusCode; 10 | 11 | header! { (Clnt, "clnt") => [String] } 12 | 13 | // in order run these test, please run following make step: 'make test-nginx-only' 14 | #[test] 15 | fn nginx_check_basic_test() { 16 | 17 | // let _result = make("test-nginx-only"); 18 | 19 | let mut response = reqwest::get("http://localhost:8000/check").unwrap(); 20 | assert!(response.status().is_success(),"nginx test check succedd"); 21 | 22 | let mut content = String::new(); 23 | response.read_to_string(&mut content); 24 | 25 | println!("response: {}",content); 26 | assert_eq!(content,"9100","should return local services"); 27 | } 28 | 29 | 30 | // force deny 31 | 32 | #[test] 33 | fn nginx_check_deny_test() { 34 | 35 | 36 | // let _result = make("test-nginx-only"); 37 | 38 | let client = reqwest::Client::new(); 39 | let mut headers = Headers::new(); 40 | headers.set(Clnt("abc".to_owned())); 41 | let mut response = client.get("http://localhost:8000/check") 42 | .headers(headers) 43 | .send() 44 | .unwrap(); 45 | 46 | 47 | assert_eq!(response.status(),StatusCode::Unauthorized,"expected 401"); 48 | 49 | } 50 | -------------------------------------------------------------------------------- /mixer-tests/tests/nginx_report_test.rs: -------------------------------------------------------------------------------- 1 | extern crate reqwest; 2 | extern crate ngx_mixer_test; 3 | 4 | #[macro_use] 5 | extern crate hyper; 6 | 7 | use ngx_mixer_test::util::make; 8 | use std::io::Read; 9 | 10 | 11 | #[test] 12 | fn nginx_report_test() { 13 | 14 | // let _result = make("test-nginx-only"); 15 | 16 | let mut response = reqwest::get("http://localhost:8000/report").unwrap(); 17 | assert!(response.status().is_success(),"nginx test check succedd"); 18 | 19 | let mut content = String::new(); 20 | response.read_to_string(&mut content); 21 | 22 | println!("response: {}",content); 23 | assert_eq!(content,"9100","should return local services"); 24 | } -------------------------------------------------------------------------------- /mixer-transport/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ngx-mixer-transport" 3 | version = "0.0.27" 4 | authors = ["Sehyo Chang sehyo@nginx.com"] 5 | 6 | 7 | 8 | [dependencies] 9 | grpc = "0.2.1" 10 | protobuf = "1.4.1" 11 | futures = "0.1.14" 12 | futures-cpupool = "0.1.5" 13 | tls-api = "0.1.8" 14 | httpbis = "0.4.1" 15 | lazy_static = "0.2.8" 16 | time = "0.1.38" 17 | base64 = "0.6.0" 18 | 19 | [build-dependencies] 20 | protoc-rust-grpc = "0.2.1" 21 | bindgen = "0.30.0" -------------------------------------------------------------------------------- /mixer-transport/build.rs: -------------------------------------------------------------------------------- 1 | extern crate protoc_rust_grpc; 2 | use std::env; 3 | 4 | const MIXER_GRPC_OUT: &str = "src/mixer_grpc"; 5 | 6 | 7 | fn generate_protoc() { 8 | protoc_rust_grpc::run(protoc_rust_grpc::Args { 9 | out_dir: MIXER_GRPC_OUT, 10 | includes: &["../protobuf"], 11 | input: &["../protobuf/mixer/v1/check.proto","../protobuf/mixer/v1/report.proto", 12 | "../protobuf/mixer/v1/attributes.proto", 13 | "../protobuf/google/rpc/status.proto","../protobuf/mixer/v1/service.proto"], 14 | rust_protobuf: true, 15 | }).expect("protoc-rust-grpc"); 16 | } 17 | 18 | fn main() { 19 | 20 | // We assume that we are in a valid directory. 21 | let path = env::current_dir().unwrap(); 22 | println!("The current directory is {}", path.display()); 23 | 24 | generate_protoc(); 25 | } 26 | -------------------------------------------------------------------------------- /mixer-transport/src/attribute/attr_wrapper.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use protobuf::well_known_types::Timestamp; 4 | use mixer_grpc::attributes::CompressedAttributes; 5 | use mixer_grpc::attributes::StringMap; 6 | use std::collections::hash_map::DefaultHasher; 7 | use std::hash::{ Hash }; 8 | use std::net::Ipv4Addr; 9 | 10 | use super::message_dict::MessageDictionary; 11 | 12 | #[allow(dead_code)] 13 | #[derive(Debug)] 14 | enum AttrValue { 15 | StrValue(String), 16 | I64(i64), 17 | Double(f64), 18 | Bool(bool), 19 | Timestamp(Timestamp), 20 | StringMap(HashMap), 21 | Ip(Ipv4Addr) 22 | } 23 | 24 | #[derive(Debug)] 25 | pub struct AttributeWrapper { 26 | 27 | values: HashMap, // map of value 28 | 29 | } 30 | 31 | 32 | impl AttributeWrapper { 33 | 34 | pub fn new() -> AttributeWrapper { 35 | AttributeWrapper { 36 | values: HashMap::new() 37 | } 38 | } 39 | 40 | #[allow(dead_code)] 41 | pub fn key_exists(&self, key: &str) -> bool { 42 | 43 | self.values.contains_key(key) 44 | } 45 | 46 | // hash the value found 47 | #[allow(dead_code)] 48 | pub fn hash(&self, key: &str,hashing: &mut DefaultHasher) { 49 | 50 | if let Some(value) = self.values.get(key) { 51 | 52 | match value { 53 | &AttrValue::StrValue(ref str_value) => { 54 | str_value.to_string().hash(hashing) 55 | }, 56 | &AttrValue::I64(int_value) => { 57 | int_value.hash(hashing) 58 | }, 59 | 60 | &AttrValue::Double(d_value) => { 61 | d_value.to_string().hash(hashing) 62 | }, 63 | 64 | &AttrValue::Bool(b_value) => { 65 | b_value.hash(hashing) 66 | }, 67 | &AttrValue::Timestamp(ref t_value) => { 68 | t_value.get_seconds().hash(hashing) 69 | }, 70 | &AttrValue::StringMap(ref str_value) => { 71 | for (_key, value) in str_value.iter() { 72 | value.hash(hashing); 73 | } 74 | }, 75 | &AttrValue::Ip(ref ip_value) => { 76 | ip_value.hash(hashing); 77 | } 78 | } 79 | 80 | } 81 | 82 | } 83 | 84 | 85 | // insert string attributes 86 | fn insert_value(&mut self, key: &str, value: AttrValue) { 87 | self.values.insert(String::from(key),value); 88 | 89 | } 90 | 91 | pub fn insert_string_attribute(&mut self, key: &str, value: &str) { 92 | if value.len() > 0 { 93 | self.insert_value(key, AttrValue::StrValue(String::from(value))); 94 | } 95 | } 96 | 97 | pub fn insert_int64_attribute(&mut self, key: &str, value: i64) { 98 | self.insert_value(key,AttrValue::I64(value)); 99 | } 100 | 101 | #[allow(dead_code)] 102 | pub fn insert_f64_attribute(&mut self, key: &str, value: f64) { 103 | self.insert_value(key,AttrValue::Double(value)); 104 | } 105 | 106 | #[allow(dead_code)] 107 | pub fn insert_bool_attribute(&mut self, key: &str, value: bool) { 108 | self.insert_value(key,AttrValue::Bool(value)); 109 | } 110 | 111 | 112 | pub fn insert_time_stamp_attribute(&mut self, key: &str, value: Timestamp) { 113 | self.insert_value(key,AttrValue::Timestamp(value)); 114 | } 115 | 116 | pub fn insert_string_map(&mut self, key: &str, value: HashMap) { 117 | self.insert_value(key,AttrValue::StringMap(value)); 118 | } 119 | 120 | pub fn insert_ip_attribute(&mut self, key:&str, value: Ipv4Addr) { 121 | self.insert_value(key,AttrValue::Ip(value)); 122 | } 123 | 124 | // generate mixer attributes 125 | pub fn as_attributes(&self, dict: &mut MessageDictionary) -> CompressedAttributes { 126 | 127 | let mut attrs = CompressedAttributes::new(); 128 | 129 | for (key,value) in &self.values { 130 | 131 | let index = dict.index_of(key); 132 | match value { 133 | &AttrValue::StrValue(ref str_value) => { 134 | attrs.mut_strings().insert(index,dict.index_of(str_value.as_str())); 135 | }, 136 | &AttrValue::I64(int_value) => { 137 | attrs.mut_int64s().insert(index,int_value); 138 | }, 139 | &AttrValue::Double(d_value) => { 140 | attrs.mut_doubles().insert(index,d_value); 141 | }, 142 | &AttrValue::Bool(b_value) => { 143 | attrs.mut_bools().insert(index,b_value); 144 | }, 145 | &AttrValue::Timestamp(ref t_value) => { 146 | attrs.mut_timestamps().insert(index,t_value.clone()); 147 | }, 148 | &AttrValue::StringMap(ref str_value) => { 149 | attrs.mut_string_maps().insert(index, map_string_map(str_value, dict)); 150 | } 151 | &AttrValue::Ip(ref ip_value) => { 152 | attrs.mut_bytes().insert(index, ip_value.octets().to_vec()); 153 | } 154 | 155 | } 156 | 157 | } 158 | 159 | for word in dict.get_words() { 160 | attrs.mut_words().push(word.clone()); 161 | } 162 | 163 | return attrs; 164 | } 165 | } 166 | 167 | // convert rust hashmap of string to stringmap 168 | fn map_string_map(string_map: &HashMap , dict: &mut MessageDictionary) -> StringMap { 169 | 170 | let mut msg = StringMap::new(); 171 | for (key, value) in string_map.iter() { 172 | msg.mut_entries().insert(dict.index_of(key),dict.index_of(value)); 173 | } 174 | 175 | return msg; 176 | 177 | } 178 | -------------------------------------------------------------------------------- /mixer-transport/src/attribute/attr_wrapper_test.rs: -------------------------------------------------------------------------------- 1 | use protobuf::well_known_types::Timestamp; 2 | use std::collections::HashMap; 3 | 4 | use super::global_dict::GlobalDictionary; 5 | use super::message_dict::MessageDictionary; 6 | use super::attr_wrapper::AttributeWrapper; 7 | 8 | const TEST_AGENT: &str = "mac123"; 9 | 10 | #[test] 11 | fn simple_string_mapping() { 12 | 13 | let global_dict = GlobalDictionary::new(); 14 | let mut dict = MessageDictionary::new(global_dict); 15 | let mut attr_wrapper = AttributeWrapper::new(); 16 | 17 | attr_wrapper.insert_string_attribute("source.ip","10.0.0.0"); 18 | attr_wrapper.insert_string_attribute("destination.ip","10.0.0.0"); 19 | 20 | let attributes = attr_wrapper.as_attributes(&mut dict); 21 | let index = attributes.get_strings().get(&0).unwrap(); 22 | assert_eq!(*index,-1); 23 | 24 | let destination_ip_index = dict.index_of("destination.ip"); 25 | let index = attributes.get_strings().get(&destination_ip_index).unwrap(); 26 | assert_eq!(*index,-1); 27 | 28 | } 29 | 30 | 31 | 32 | #[test] 33 | fn test_attr_key_exists() { 34 | 35 | let mut attr_wrapper = AttributeWrapper::new(); 36 | 37 | attr_wrapper.insert_string_attribute("source.ip","10.0.0.0"); 38 | attr_wrapper.insert_string_attribute("destination.ip","10.0.0.0"); 39 | 40 | assert!(attr_wrapper.key_exists("source.ip")); 41 | assert!(!attr_wrapper.key_exists("source4.ip")); 42 | } 43 | 44 | 45 | #[test] 46 | fn simple_int64_mapping() { 47 | 48 | let global_dict = GlobalDictionary::new(); 49 | let mut dict = MessageDictionary::new(global_dict); 50 | let mut attr_wrapper = AttributeWrapper::new(); 51 | 52 | attr_wrapper.insert_int64_attribute("response.duration",50); 53 | 54 | let attributes = attr_wrapper.as_attributes(&mut dict); 55 | let response_dur_index = dict.index_of("response.duration"); 56 | let duration = attributes.get_int64s().get(&response_dur_index).unwrap(); 57 | assert_eq!(*duration,50); 58 | } 59 | 60 | #[test] 61 | fn simple_double_mapping() { 62 | 63 | let global_dict = GlobalDictionary::new(); 64 | let mut dict = MessageDictionary::new(global_dict); 65 | let mut attr_wrapper = AttributeWrapper::new(); 66 | 67 | attr_wrapper.insert_f64_attribute("response.duration", 0.5_f64); 68 | 69 | let attributes = attr_wrapper.as_attributes(&mut dict); 70 | let response_dur_index = dict.index_of("response.duration"); 71 | let duration = attributes.get_doubles().get(&response_dur_index).unwrap(); 72 | assert_eq!(*duration,0.5_f64); 73 | } 74 | 75 | #[test] 76 | fn simple_bool_mapping() { 77 | 78 | let global_dict = GlobalDictionary::new(); 79 | let mut dict = MessageDictionary::new(global_dict); 80 | let mut attr_wrapper = AttributeWrapper::new(); 81 | 82 | attr_wrapper.insert_bool_attribute("true", true); 83 | 84 | let attributes = attr_wrapper.as_attributes(&mut dict); 85 | let response_dur_index = dict.index_of("true"); 86 | let duration = attributes.get_bools().get(&response_dur_index).unwrap(); 87 | assert_eq!(*duration,true); 88 | } 89 | 90 | #[test] 91 | fn simple_time_stamp() { 92 | 93 | let global_dict = GlobalDictionary::new(); 94 | let mut dict = MessageDictionary::new(global_dict); 95 | let mut attr_wrapper = AttributeWrapper::new(); 96 | 97 | let mut request_time = Timestamp::new(); 98 | request_time.set_seconds(1000); 99 | attr_wrapper.insert_time_stamp_attribute("request.time", request_time); 100 | 101 | let attributes = attr_wrapper.as_attributes(&mut dict); 102 | let response_dur_index = dict.index_of("request.time"); 103 | let duration = attributes.get_timestamps().get(&response_dur_index).unwrap(); 104 | 105 | assert_eq!(duration.get_seconds(),1000); 106 | } 107 | 108 | 109 | 110 | #[test] 111 | fn simple_stringmap_mapping() { 112 | let global_dict = GlobalDictionary::new(); 113 | let mut dict = MessageDictionary::new(global_dict); 114 | let mut attr_wrapper = AttributeWrapper::new(); 115 | 116 | let mut string_map: HashMap = HashMap::new(); 117 | string_map.insert(String::from("request.scheme"), String::from("http")); 118 | string_map.insert(String::from("request.useragent"), String::from(TEST_AGENT)); 119 | attr_wrapper.insert_string_map("request.headers", string_map); 120 | 121 | let attributes = attr_wrapper.as_attributes(&mut dict); 122 | 123 | let str_map = attributes.get_string_maps().get(&dict.index_of("request.headers")).unwrap(); 124 | let str_http_index = str_map.get_entries().get(&dict.index_of("request.scheme")).unwrap(); 125 | assert_eq!(*str_http_index, dict.index_of("http")); 126 | 127 | let mac_index = dict.index_of(TEST_AGENT); 128 | println!("mac index: {}",mac_index); 129 | println!("words: {:?}",attributes.get_words()); 130 | assert_eq!(attributes.get_words().get( (mac_index * -1 -1 ) as usize ).unwrap(),TEST_AGENT); 131 | } 132 | -------------------------------------------------------------------------------- /mixer-transport/src/attribute/global_dict.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::collections::HashMap; 3 | 4 | // This is from global_dictionary.yaml 5 | 6 | 7 | pub const REQUEST_HEADER: &str = "request.headers"; 8 | pub const TARGET_SERVICE: &str = "target.service"; 9 | pub const REQUEST_HOST: &str = "request.host"; 10 | pub const REQUEST_METHOD: &str = "request.method"; 11 | pub const REQUEST_PATH: &str = "request.path"; 12 | pub const REQUEST_REFER: &str = "request.referer"; 13 | pub const REQUEST_SCHEME: &str = "request.scheme"; 14 | pub const REQUEST_SIZE: &str = "request.size"; 15 | pub const REQUEST_TIME: &str = "request.time"; 16 | pub const REQUEST_USERAGENT: &str = "request.useragent"; 17 | pub const RESPONSE_CODE: &str = "response.code"; 18 | pub const RESPONSE_DURATION: &str = "response.duration"; 19 | pub const RESPONSE_SIZE: &str = "response.size"; 20 | pub const RESPONSE_HEADERS: &str = "response.headers"; 21 | pub const SOURCE_IP: &str = "source.ip"; 22 | pub const SOURCE_UID: &str = "source.uid"; 23 | pub const SOURCE_PORT: &str = "source.port"; 24 | pub const SOURCE_SERVICE: &str = "source.service"; 25 | pub const SOURCE_LABELS: &str = "source.labels"; 26 | pub const SRC_IP_HEADER: &str = "X-ISTIO-SRC-IP"; 27 | pub const SRC_UID_HEADER: &str = "X-ISTIO-SRC-UID"; 28 | pub const DESTINATION_SERVICE: &str = "destination.service"; 29 | pub const DESTINATION_UID: &str = "destination.uid"; 30 | pub const DESTINATION_IP: &str = "destination.ip"; 31 | pub const DESTINATION_LABELS: &str = "destination.labels"; 32 | pub const CONTEXT_PROTOCOL: &str = "context.protocol"; 33 | 34 | 35 | 36 | const GLOBAL_LIST: [&'static str; 159] = [ 37 | "source.ip", 38 | "source.port", 39 | "source.name", 40 | "source.uid", 41 | "source.namespace", 42 | "source.labels", 43 | "source.user", 44 | "target.ip", 45 | "target.port", 46 | "target.service", 47 | "target.name", 48 | "target.uid", 49 | "target.namespace", 50 | "target.labels", 51 | "target.user", 52 | "request.headers", 53 | "request.id", 54 | "request.path", 55 | "request.host", 56 | "request.method", 57 | "request.reason", 58 | "request.referer", 59 | "request.scheme", 60 | "request.size", 61 | "request.time", 62 | "request.useragent", 63 | "response.headers", 64 | "response.size", 65 | "response.time", 66 | "response.duration", 67 | "response.code", 68 | ":authority", 69 | ":method", 70 | ":path", 71 | ":scheme", 72 | ":status", 73 | "access-control-allow-origin", 74 | "access-control-allow-methods", 75 | "access-control-allow-headers", 76 | "access-control-max-age", 77 | "access-control-request-method", 78 | "access-control-request-headers", 79 | "accept-charset", 80 | "accept-encoding", 81 | "accept-language", 82 | "accept-ranges", 83 | "accept", 84 | "access-control-allow", 85 | "age", 86 | "allow", 87 | "authorization", 88 | "cache-control", 89 | "content-disposition", 90 | "content-encoding", 91 | "content-language", 92 | "content-length", 93 | "content-location", 94 | "content-range", 95 | "content-type", 96 | "cookie", 97 | "date", 98 | "etag", 99 | "expect", 100 | "expires", 101 | "from", 102 | "host", 103 | "if-match", 104 | "if-modified-since", 105 | "if-none-match", 106 | "if-range", 107 | "if-unmodified-since", 108 | "keep-alive", 109 | "last-modified", 110 | "link", 111 | "location", 112 | "max-forwards", 113 | "proxy-authenticate", 114 | "proxy-authorization", 115 | "range", 116 | "referer", 117 | "refresh", 118 | "retry-after", 119 | "server", 120 | "set-cookie", 121 | "strict-transport-sec", 122 | "transfer-encoding", 123 | "user-agent", 124 | "vary", 125 | "via", 126 | "www-authenticate", 127 | "GET", 128 | "POST", 129 | "http", 130 | "envoy", 131 | "'200'", 132 | "Keep-Alive", 133 | "chunked", 134 | "x-envoy-service-time", 135 | "x-forwarded-for", 136 | "x-forwarded-host", 137 | "x-forwarded-proto", 138 | "x-http-method-override", 139 | "x-request-id", 140 | "x-requested-with", 141 | "application/json", 142 | "application/xml", 143 | "gzip", 144 | "text/html", 145 | "text/html; charset=utf-8", 146 | "text/plain", 147 | "text/plain; charset=utf-8", 148 | "'0'", 149 | "'1'", 150 | "true", 151 | "false", 152 | "gzip, deflate", 153 | "max-age=0", 154 | "x-envoy-upstream-service-time", 155 | "x-envoy-internal", 156 | "x-envoy-expected-rq-timeout-ms", 157 | "x-ot-span-context", 158 | "x-b3-traceid", 159 | "x-b3-sampled", 160 | "x-b3-spanid", 161 | "tcp", 162 | "connection.id", 163 | "connection.received.bytes", 164 | "connection.received.bytes_total", 165 | "connection.sent.bytes", 166 | "connection.sent.bytes_total", 167 | "connection.duration", 168 | "context.protocol", 169 | "context.timestamp", 170 | "context.time", 171 | "0", 172 | "1", 173 | "200", 174 | "302", 175 | "400", 176 | "401", 177 | "403", 178 | "404", 179 | "409", 180 | "429", 181 | "499", 182 | "500", 183 | "501", 184 | "502", 185 | "503", 186 | "504", 187 | "destination.ip", 188 | "destination.port", 189 | "destination.service", 190 | "destination.name", 191 | "destination.uid", 192 | "destination.namespace", 193 | "destination.labels", 194 | "destination.user", 195 | "source.service", 196 | ]; 197 | 198 | #[allow(dead_code,non_snake_case)] 199 | pub fn Get_Global_Words() -> [&'static str; 159] { 200 | GLOBAL_LIST 201 | } 202 | 203 | 204 | pub struct GlobalDictionary { 205 | 206 | global_dict: HashMap, 207 | 208 | #[allow(dead_code)] 209 | top_index: i32 210 | } 211 | 212 | impl GlobalDictionary { 213 | 214 | // Create new instance of GlobalDictionary 215 | pub fn new() -> GlobalDictionary { 216 | 217 | // Get global list of keywords 218 | let global_words = GLOBAL_LIST; 219 | let mut global_dict: HashMap = HashMap::new(); 220 | // Copy list of keywords into global dictionary hashMap 221 | for i in 0..global_words.len() { 222 | let key = GLOBAL_LIST[i]; 223 | global_dict.insert(String::from(key),i as i32); 224 | } 225 | 226 | GlobalDictionary { 227 | global_dict, 228 | top_index: global_words.len() as i32 229 | } 230 | } 231 | 232 | // find index in the global dictionary 233 | pub fn index_of(&self, name: &str ) -> Option<&i32> { 234 | self.global_dict.get(name) 235 | } 236 | 237 | 238 | pub fn size(&self) -> usize { 239 | GLOBAL_LIST.len() 240 | } 241 | 242 | } 243 | 244 | 245 | 246 | -------------------------------------------------------------------------------- /mixer-transport/src/attribute/global_dict_test.rs: -------------------------------------------------------------------------------- 1 | use super::global_dict::GlobalDictionary; 2 | 3 | #[test] 4 | fn test_global_simple() { 5 | 6 | let dict = GlobalDictionary::new(); 7 | let index = dict.index_of("source.port").unwrap(); 8 | assert_eq!(*index,1,"check source port"); 9 | let index = dict.index_of("source.service").unwrap(); 10 | assert_eq!(*index,158,"check source service"); 11 | } 12 | -------------------------------------------------------------------------------- /mixer-transport/src/attribute/message_dict.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use super::global_dict::GlobalDictionary; 3 | 4 | pub struct MessageDictionary { 5 | 6 | global_dict: GlobalDictionary, 7 | message_words: Vec, 8 | message_dict: HashMap 9 | } 10 | 11 | // return public index of the message which is negative per API 12 | fn message_dict_index( idx: i32) -> i32 { 13 | return -(idx + 1); 14 | } 15 | 16 | impl MessageDictionary { 17 | 18 | pub fn new(global_dict: GlobalDictionary) -> MessageDictionary { 19 | 20 | MessageDictionary { 21 | global_dict, 22 | message_words: Vec::new(), 23 | message_dict: HashMap::new() 24 | } 25 | 26 | } 27 | 28 | pub fn get_words(&self) -> &Vec { 29 | return &self.message_words; 30 | } 31 | 32 | //find index, try look up in the global, otherwise look up in the local 33 | pub fn index_of(&mut self, name: &str) -> i32 { 34 | 35 | if let Some(index) = self.global_dict.index_of(name) { 36 | return *index; 37 | } 38 | 39 | if let Some(index) = self.message_dict.get(name) { 40 | return message_dict_index(*index); 41 | } 42 | 43 | let index = self.message_words.len() as i32; 44 | self.message_words.push(String::from(name)); 45 | self.message_dict.insert(String::from(name),index as i32 ); 46 | 47 | message_dict_index(index) 48 | 49 | } 50 | 51 | pub fn global_dict_size(&self) -> usize { 52 | self.global_dict.size() 53 | } 54 | 55 | } 56 | 57 | 58 | -------------------------------------------------------------------------------- /mixer-transport/src/attribute/message_dict_test.rs: -------------------------------------------------------------------------------- 1 | use super::global_dict::GlobalDictionary; 2 | use super::message_dict::MessageDictionary; 3 | 4 | // test for accessing global dictionary 5 | #[test] 6 | fn test_message_dict_global() { 7 | let global_dict = GlobalDictionary::new(); 8 | let mut dict = MessageDictionary::new(global_dict); 9 | let index = dict.index_of("source.port"); 10 | assert_eq!(index, 1, "check source port"); 11 | } 12 | 13 | // test if we are adding new message word 14 | #[test] 15 | fn test_message_dict_local_first() { 16 | let global_dict = GlobalDictionary::new(); 17 | let mut dict = MessageDictionary::new(global_dict); 18 | assert_eq!(dict.index_of("unknown.x"),-1,"check new"); 19 | assert_eq!(dict.index_of("unknown.x"),-1,"check new"); // existing 20 | assert_eq!(dict.index_of("unknown.y"),-2,"check new"); // new 21 | } 22 | -------------------------------------------------------------------------------- /mixer-transport/src/attribute/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | pub mod attr_wrapper; 3 | pub mod global_dict; 4 | pub mod message_dict; 5 | 6 | 7 | #[cfg(test)] 8 | mod global_dict_test; 9 | 10 | #[cfg(test)] 11 | mod message_dict_test; 12 | 13 | #[cfg(test)] 14 | mod attr_wrapper_test; -------------------------------------------------------------------------------- /mixer-transport/src/bin/report_client.rs: -------------------------------------------------------------------------------- 1 | /** 2 | test sending of report 3 | */ 4 | 5 | 6 | extern crate ngx_mixer_transport; 7 | extern crate grpc; 8 | extern crate futures; 9 | 10 | use std::collections::HashMap; 11 | // use ngx_mixer_module::mixer::service_grpc::MixerClient; 12 | // use ngx_mixer_module::mixer::report::ReportRequest; 13 | // use ngx_mixer_module::mixer::attributes::Attributes; 14 | //use ngx_mixer_module::mixer::service_grpc::Mixer; 15 | 16 | 17 | static REQUEST_HEADER: i32 = 0; 18 | static TARGET_SERVICE: i32 = 1; 19 | static REQUEST_HOST: i32 = 2; 20 | 21 | 22 | fn main() { 23 | 24 | println!("creating mixer client at local host"); 25 | 26 | //let client = MixerClient::new_plain("localhost", 9091, Default::default()).expect("init"); 27 | 28 | 29 | // let mut rf = RepeatedField::default(); 30 | // let attr = Attributes::new(); 31 | //attr.set_string_attributes("") 32 | 33 | let mut dict_values: HashMap = HashMap::new(); 34 | dict_values.insert(REQUEST_HEADER,String::from("request.headers")); 35 | dict_values.insert(TARGET_SERVICE,String::from("target.service")); 36 | dict_values.insert(REQUEST_HOST,String::from("request.host")); 37 | // attr.set_dictionary(dict_values); 38 | 39 | let mut string_values: HashMap = HashMap::new(); 40 | string_values.insert(TARGET_SERVICE,String::from("reviews.default.svc.cluster.local")); 41 | string_values.insert(REQUEST_HOST,String::from("test.com")); 42 | // attr.set_string_attributes(string_values); 43 | 44 | 45 | // req.set_attribute_update(attr); 46 | 47 | 48 | // rf.push(req); 49 | 50 | 51 | // let resp = client.report(grpc::RequestOptions::new(), req); 52 | ; 53 | 54 | 55 | // println!("send report request: {} count",resp.wait_drop_metadata().count()); 56 | } 57 | -------------------------------------------------------------------------------- /mixer-transport/src/istio_client/cache_elem.rs: -------------------------------------------------------------------------------- 1 | use transport::status::Status; 2 | use std::time::{Duration, SystemTime}; 3 | 4 | // simple LRU Cache, index by hash 5 | 6 | pub struct CacheElem { 7 | status: Status, 8 | expire_time: SystemTime, 9 | use_count: u32, 10 | } 11 | 12 | 13 | impl Clone for CacheElem { 14 | 15 | fn clone(&self) -> Self { 16 | CacheElem { 17 | status: self.status.clone(), 18 | expire_time: self.expire_time.clone(), 19 | use_count: self.use_count.clone() 20 | } 21 | } 22 | } 23 | 24 | #[allow(dead_code)] 25 | impl CacheElem { 26 | 27 | pub fn new() -> CacheElem { 28 | CacheElem { 29 | status: Status::new(), 30 | expire_time: SystemTime::now() + Duration::new(3200*24, 0), 31 | use_count: 0 32 | } 33 | } 34 | 35 | pub fn with_status_expired(status: Status, expire_time: SystemTime) -> CacheElem { 36 | CacheElem { 37 | status, 38 | expire_time, 39 | use_count: 0 40 | } 41 | } 42 | 43 | 44 | // check if value is expired 45 | pub fn is_expired(&self, time: SystemTime) -> bool { 46 | time >= self.expire_time 47 | } 48 | 49 | pub fn get_status(&self) -> Status { 50 | self.status.clone() 51 | } 52 | 53 | } 54 | 55 | 56 | #[test] 57 | fn test_is_expired() { 58 | 59 | let elem = CacheElem::new(); 60 | assert!(!elem.is_expired(SystemTime::now()),"should not expired"); 61 | 62 | let elem = CacheElem::with_status_expired(Status::new(),SystemTime::now() + Duration::new(1000,0)); 63 | assert!(!elem.is_expired(SystemTime::now()),"should not expired"); 64 | } 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /mixer-transport/src/istio_client/check_cache.rs: -------------------------------------------------------------------------------- 1 | #![feature(conservative_impl_trait)] 2 | 3 | use std::time::{ SystemTime}; 4 | use std::collections::HashMap; 5 | use std::clone::Clone; 6 | 7 | use mixer_grpc::check::CheckResponse; 8 | use transport::status::{ Status, StatusCodeEnum} ; 9 | use super::options::CheckOptions; 10 | use attribute::attr_wrapper::AttributeWrapper; 11 | use super::lru_cache::LRUCache; 12 | use super::referenced::Referenced; 13 | 14 | 15 | #[allow(dead_code)] 16 | fn on_response(cache: &CheckCache,status: Status,_result: &mut CheckResult, attributes: &AttributeWrapper, response: &CheckResponse) -> Status { 17 | 18 | if !status.ok() { 19 | if cache.options.network_fail_open { 20 | return Status::new(); 21 | } else { 22 | return status; 23 | } 24 | } else { 25 | return cache.cache_response(attributes,response,SystemTime::now()); 26 | } 27 | 28 | } 29 | 30 | #[allow(dead_code)] 31 | pub struct CheckCache { 32 | 33 | options: CheckOptions, 34 | cache: LRUCache, 35 | referenced_map: HashMap 36 | } 37 | 38 | 39 | #[allow(dead_code)] 40 | impl CheckCache { 41 | 42 | 43 | pub fn new() -> CheckCache { 44 | CheckCache { 45 | options: CheckOptions::new(), 46 | cache: LRUCache::new(), 47 | referenced_map: HashMap::new() 48 | } 49 | } 50 | 51 | 52 | pub fn check(&self, attributes: &AttributeWrapper) -> CheckResult{ 53 | 54 | 55 | let mut result = CheckResult::new(on_response); 56 | let status = self.check_attribute_time(attributes, SystemTime::now()); 57 | if status.get_error_code() != StatusCodeEnum::NOT_FOUND { 58 | result.set_status(status); 59 | } 60 | 61 | result 62 | 63 | } 64 | 65 | 66 | fn cache_response(&self, _attributes: &AttributeWrapper, _response: &CheckResponse, _time_now: SystemTime) -> Status { 67 | return Status::new() 68 | } 69 | 70 | // check attribute for time 71 | // Status CheckCache::Check(const Attributes& attributes, Tick time_now) 72 | fn check_attribute_time(&self, attributes: &AttributeWrapper, tick: SystemTime) -> Status { 73 | 74 | 75 | for( _key,reference) in &self.referenced_map { 76 | 77 | let some_signature = reference.signature(attributes,""); 78 | 79 | match some_signature { 80 | None => continue, 81 | Some(signature) => { 82 | if let Some(value) = self.cache.get(signature) { 83 | if value.is_expired(tick) { 84 | self.cache.remove(signature); 85 | return Status::with_code(StatusCodeEnum::NOT_FOUND) 86 | } 87 | 88 | return value.get_status(); 89 | } 90 | } 91 | 92 | } 93 | 94 | } 95 | 96 | return Status::with_code(StatusCodeEnum::NOT_FOUND) 97 | } 98 | 99 | 100 | } 101 | 102 | 103 | #[allow(dead_code)] 104 | pub struct CheckResult { 105 | 106 | status: Status, 107 | on_response: fn(cache: &CheckCache,status: Status,result: &mut CheckResult, attributes: &AttributeWrapper, response: &CheckResponse) -> Status 108 | 109 | } 110 | 111 | #[allow(dead_code)] 112 | impl CheckResult { 113 | 114 | pub fn new( on_response: fn(cache: &CheckCache,status: Status,result: &mut CheckResult,attributes: &AttributeWrapper, response: &CheckResponse) -> Status) -> CheckResult { 115 | CheckResult { 116 | status: Status::new(), 117 | on_response 118 | } 119 | } 120 | 121 | 122 | pub fn is_cache_hit(&self) -> bool { 123 | self.status.get_error_code() as i32 != StatusCodeEnum::UNAVAILABLE as i32 124 | } 125 | 126 | pub fn get_status(&self) -> Status { 127 | self.status.clone() 128 | } 129 | 130 | pub fn set_status( &mut self, status: Status) { 131 | self.status = status; 132 | } 133 | 134 | 135 | 136 | pub fn set_response(&mut self, cache: &CheckCache,status: Status,attributes: &AttributeWrapper, response: &CheckResponse) { 137 | let handler = self.on_response; 138 | let status = handler(cache, status,self,attributes,response); 139 | self.set_status(status); 140 | } 141 | 142 | /* 143 | if(response.has_precondition()) { 144 | 145 | if(response.get_precondition().has_precondition()) { 146 | expire_time_ = 147 | time_now + ToMilliseonds(response.precondition().valid_duration()); 148 | } 149 | } 150 | 151 | 152 | let condition = response.get_precondition(); 153 | let attributes = condition.get_attributes(); 154 | let status = condition.get_status(); 155 | let valid_duration = condition.get_valid_duration(); 156 | let use_count = condition.get_valid_use_count(); 157 | let ref_attr = condition.get_referenced_attributes(); 158 | // let quota = response.get_quotas(); 159 | 160 | log(&format!("check attributes :{:?} ",attributes)); 161 | log(&format!("check ref attributes :{:?} ",ref_attr)); 162 | log(&format!("success calling check status:{:?}, duration: {:?}", 163 | status,valid_duration)); 164 | 165 | let words = ref_attr.get_words(); 166 | let matches = ref_attr.get_attribute_matches(); 167 | log(&format!(" ref attr words :{:?} ",words)); 168 | log(&format!(" ref attr matches :{:?} ",matches)); 169 | 170 | for condition in matches { 171 | 172 | let name = condition.get_name(); 173 | let condition = condition.get_condition(); 174 | 175 | log(&format!("condition name :{:?} ",name)); 176 | 177 | match condition { 178 | ReferencedAttributes_Condition::CONDITION_UNSPECIFIED => { 179 | log(&format!("unspecified")) 180 | }, 181 | ReferencedAttributes_Condition::ABSENCE => { 182 | log(&format!("absence")) 183 | }, 184 | ReferencedAttributes_Condition::EXACT => { 185 | log(&format!("exact")) 186 | } 187 | ReferencedAttributes_Condition::REGEX => { 188 | log(&format!("regex")) 189 | } 190 | } 191 | 192 | } 193 | */ 194 | 195 | 196 | 197 | } 198 | 199 | #[allow(dead_code)] 200 | fn test_response1(_cache: &CheckCache,_status: Status,_result: &mut CheckResult, _attributes: &AttributeWrapper, _response: &CheckResponse) -> Status { 201 | Status::new() 202 | } 203 | 204 | 205 | #[test] 206 | fn test_check_result_cache_hit() { 207 | 208 | 209 | let cache_result = CheckResult::new(test_response1); 210 | assert_eq!(cache_result.is_cache_hit(),true); 211 | } 212 | 213 | #[allow(dead_code)] 214 | fn test_response2(_cache: &CheckCache,_status: Status,_result: &mut CheckResult, _attributes: &AttributeWrapper, _response: &CheckResponse) -> Status { 215 | _status 216 | } 217 | 218 | #[test] 219 | fn test_check_result_set_response() { 220 | 221 | 222 | let mut check_result = CheckResult::new(test_response2); 223 | check_result.set_response( &CheckCache::new(),Status::with_code(StatusCodeEnum::CANCELLED), &AttributeWrapper::new(),&CheckResponse::new()); 224 | 225 | assert_eq!(check_result.get_status().get_error_code(), StatusCodeEnum::CANCELLED,"status should be cancelled"); 226 | } 227 | -------------------------------------------------------------------------------- /mixer-transport/src/istio_client/check_cache_test.rs: -------------------------------------------------------------------------------- 1 | 2 | 3 | use super::check_cache::CheckCache; 4 | 5 | -------------------------------------------------------------------------------- /mixer-transport/src/istio_client/check_options_test.rs: -------------------------------------------------------------------------------- 1 | use istio_client::options::CheckOptions; 2 | use istio_client::options::ReportOptions; 3 | 4 | #[test] 5 | fn test_check_options() { 6 | 7 | let ck_opt = CheckOptions::new(); 8 | assert_eq!(ck_opt.network_fail_open,true); 9 | assert_eq!(ck_opt.num_entries,10000); 10 | } 11 | 12 | #[test] 13 | fn test_report_options() { 14 | let rep_options = ReportOptions::new(); 15 | assert_eq!(rep_options.max_batch_entries,1000); 16 | } 17 | 18 | -------------------------------------------------------------------------------- /mixer-transport/src/istio_client/lru_cache.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::sync::{Arc, Mutex, MutexGuard }; 3 | use super::cache_elem::CacheElem; 4 | 5 | // simple LRU Cache, index by hash 6 | 7 | 8 | pub struct LRUCache { 9 | 10 | values: Arc>> 11 | } 12 | 13 | impl LRUCache { 14 | 15 | pub fn new() -> LRUCache { 16 | LRUCache{ 17 | values: Arc::new(Mutex::new(HashMap::new())) 18 | } 19 | } 20 | 21 | 22 | pub fn get(&self, key: u64) -> Option { 23 | let map: MutexGuard> = self.values.lock().unwrap(); 24 | let result: Option<&CacheElem> = map.get(&key); 25 | if let Some(ref value) = result { 26 | let z: &CacheElem = value; 27 | let clone_value: CacheElem = z.clone(); 28 | return Some(clone_value); 29 | } 30 | None 31 | } 32 | 33 | 34 | pub fn remove(&self, key: u64) { 35 | self.values.lock().unwrap().remove(&key); 36 | } 37 | 38 | 39 | 40 | } -------------------------------------------------------------------------------- /mixer-transport/src/istio_client/mixer_client_wrapper.rs: -------------------------------------------------------------------------------- 1 | /** 2 | * mixer client, based on Istio mixer client implementation 3 | */ 4 | extern crate futures; 5 | extern crate grpc; 6 | 7 | use futures::future::Future; 8 | use super::options::{ CheckOptions, ReportOptions, QuotaOptions }; 9 | use super::check_cache:: { CheckCache } ; 10 | use super::quota_cache::QuotaCache; 11 | use transport::status:: { Status }; 12 | use transport::mixer_grpc::Transport; 13 | use mixer_grpc::check:: { CheckRequest, CheckResponse} ; 14 | use attribute::global_dict::GlobalDictionary; 15 | use attribute::message_dict::MessageDictionary; 16 | 17 | #[allow(dead_code)] 18 | pub struct MixerClientOptions { 19 | 20 | check_options: CheckOptions, 21 | report_options: ReportOptions, 22 | quota_options: QuotaOptions 23 | 24 | } 25 | 26 | impl MixerClientOptions { 27 | 28 | pub fn new() -> MixerClientOptions { 29 | 30 | MixerClientOptions{ 31 | check_options: CheckOptions::new(), 32 | report_options: ReportOptions::new(), 33 | quota_options: QuotaOptions::new() 34 | } 35 | } 36 | } 37 | 38 | 39 | #[allow(dead_code)] 40 | pub struct MixerClientWrapper { 41 | 42 | options: MixerClientOptions, 43 | check_cache: CheckCache, 44 | quota_cache: QuotaCache 45 | } 46 | 47 | impl MixerClientWrapper { 48 | 49 | pub fn new() -> MixerClientWrapper { 50 | 51 | MixerClientWrapper{ 52 | options: MixerClientOptions::new(), 53 | check_cache: CheckCache::new(), 54 | quota_cache: QuotaCache::new() 55 | } 56 | } 57 | 58 | 59 | pub fn check(&self,transport: T) -> Box> { 60 | //pub fn check(&self,transport: T) -> grpc::SingleResponse { 61 | 62 | let attribute_wrapper = transport.get_attributes(); 63 | 64 | /* 65 | TODO: implement cache, 66 | this should return future with immediate value 67 | let result = self.check_cache.check(attribute_wrapper); 68 | if result.is_cache_hit() && !result.get_status().ok() { 69 | // on_done(check_result->status()); 70 | return Status::with_code(StatusCodeEnum::NOT_FOUND); 71 | 72 | } 73 | */ 74 | 75 | 76 | // prepare input for check 77 | let mut message_dict = MessageDictionary::new(GlobalDictionary::new()); 78 | let attributes = attribute_wrapper.as_attributes(&mut message_dict); 79 | 80 | let mut check_request = CheckRequest::new(); 81 | check_request.set_attributes(attributes); 82 | check_request.set_global_word_count(message_dict.global_dict_size() as u32); 83 | 84 | //log(&format!("ready to send check")); 85 | 86 | transport.check(check_request) 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /mixer-transport/src/istio_client/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | pub mod check_cache; 3 | 4 | mod quota_cache; 5 | mod lru_cache; 6 | mod referenced; 7 | mod cache_elem; 8 | 9 | pub mod options; 10 | pub mod mixer_client_wrapper; 11 | 12 | 13 | #[cfg(test)] 14 | mod check_options_test; 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /mixer-transport/src/istio_client/options.rs: -------------------------------------------------------------------------------- 1 | // This is from ISTIO mixerclient/include/options.h 2 | 3 | // Options controlling check behavior. 4 | pub struct CheckOptions { 5 | 6 | // Maximum number of cache entries kept in the cache. 7 | // Set to 0 will disable caching. 8 | pub num_entries: u32, 9 | 10 | // If true, Check is passed for any network failures. 11 | pub network_fail_open: bool 12 | } 13 | 14 | #[allow(dead_code)] 15 | impl CheckOptions { 16 | 17 | pub fn new() -> CheckOptions { 18 | CheckOptions { 19 | num_entries: 10000, 20 | network_fail_open: true 21 | } 22 | } 23 | 24 | pub fn num_entries(cache_entries: u32) -> CheckOptions { 25 | CheckOptions { 26 | num_entries: cache_entries, 27 | network_fail_open: true 28 | } 29 | } 30 | 31 | } 32 | 33 | 34 | // Options controlling report batch. 35 | pub struct ReportOptions { 36 | 37 | // Maximum number of reports to be batched. 38 | pub max_batch_entries: u32, 39 | 40 | // Maximum milliseconds a report item stayed in the buffer for batching. 41 | pub max_batch_time_ms: u32 42 | } 43 | 44 | impl ReportOptions { 45 | 46 | // // Default to batch up to 1000 reports or 1 seconds. 47 | pub fn new() -> ReportOptions { 48 | ReportOptions { 49 | max_batch_entries: 1000, 50 | max_batch_time_ms: 1000 51 | } 52 | } 53 | 54 | } 55 | 56 | 57 | // Options controlling quota behavior. 58 | pub struct QuotaOptions { 59 | 60 | 61 | // Maximum number of cache entries kept in the cache. 62 | // Set to 0 will disable caching. 63 | pub num_entries: u32, 64 | 65 | // Maximum milliseconds before an idle cached quota should be deleted. 66 | pub expiration_ms: u32 67 | } 68 | 69 | impl QuotaOptions { 70 | 71 | pub fn new() -> QuotaOptions { 72 | QuotaOptions { 73 | num_entries: 10000, 74 | expiration_ms: 600000 75 | } 76 | } 77 | } 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /mixer-transport/src/istio_client/quota_cache.rs: -------------------------------------------------------------------------------- 1 | pub struct QuotaCache { 2 | 3 | } 4 | 5 | impl QuotaCache { 6 | 7 | pub fn new() -> QuotaCache { 8 | QuotaCache {} 9 | } 10 | } -------------------------------------------------------------------------------- /mixer-transport/src/istio_client/referenced.rs: -------------------------------------------------------------------------------- 1 | use std::vec::Vec; 2 | 3 | use mixer_grpc::check::{ ReferencedAttributes, ReferencedAttributes_Condition } ; 4 | use attribute::global_dict::Get_Global_Words; 5 | use attribute::attr_wrapper::AttributeWrapper; 6 | use std::collections::hash_map::DefaultHasher; 7 | use std::hash::{Hash, Hasher}; 8 | 9 | #[allow(dead_code)] 10 | pub struct Referenced { 11 | 12 | absence_keys: Vec, 13 | exact_keys: Vec 14 | } 15 | 16 | #[allow(dead_code)] 17 | impl Referenced { 18 | 19 | pub fn new() -> Referenced { 20 | Referenced { 21 | absence_keys: vec![], 22 | exact_keys: vec![] 23 | } 24 | } 25 | 26 | 27 | pub fn fill(&mut self, reference: &ReferencedAttributes) -> bool { 28 | let global_words = Get_Global_Words(); 29 | let mut name: &str; 30 | 31 | for attr_match in reference.get_attribute_matches() { 32 | let idx = attr_match.get_name() as usize; 33 | if idx >= 0 { 34 | if idx >= global_words.len() { 35 | //log(&format!("Global word index is too big: {}, >= {}", idx, global_words.len())); 36 | return false; 37 | } 38 | name = global_words[idx]; 39 | } else { 40 | // per-message index is negative, its format is: 41 | // per_message_idx = -(array_idx + 1) 42 | let m_idx = (- (idx as i32) - 1) as usize; 43 | if m_idx >= reference.get_words().len() as usize { 44 | //log(&format!("Per message word index is too big: {}, >= {}", idx, reference.get_words().len())); 45 | return false; 46 | } 47 | name = &reference.get_words()[m_idx]; 48 | } 49 | 50 | match attr_match.get_condition() { 51 | ReferencedAttributes_Condition::ABSENCE => self.absence_keys.push(name.to_string()), 52 | ReferencedAttributes_Condition::EXACT => self.exact_keys.push(name.to_string()), 53 | ReferencedAttributes_Condition::REGEX => { 54 | // log(&format!("Received REGEX in Reference Attributes {}", name)); 55 | return false; 56 | }, 57 | _ => {} 58 | } 59 | } 60 | 61 | true 62 | } 63 | 64 | // compute signature based on attribute content and extra key provided 65 | 66 | pub fn signature(&self, attributes: &AttributeWrapper, extra_key: &str) -> Option { 67 | // if an "absence" key exists, return false for mis-match. 68 | for key in &self.absence_keys { 69 | if attributes.key_exists(&key) { 70 | return None; 71 | } 72 | } 73 | 74 | let mut hashing = DefaultHasher::new(); 75 | 76 | for key in &self.exact_keys { 77 | attributes.hash(&key, &mut hashing); 78 | } 79 | 80 | extra_key.hash(&mut hashing); 81 | 82 | let hash_value = hashing.finish(); 83 | 84 | return Some(hash_value) 85 | } 86 | } 87 | 88 | impl Hash for Referenced { 89 | 90 | fn hash(&self, state: &mut H) { 91 | 92 | let mut sorted_absence_keys = self.absence_keys.clone(); 93 | sorted_absence_keys.sort(); 94 | 95 | for key in sorted_absence_keys { 96 | key.hash(state); 97 | } 98 | 99 | let mut sorted_exact_keys = self.exact_keys.clone(); 100 | sorted_exact_keys.sort(); 101 | 102 | for key in sorted_exact_keys { 103 | key.hash(state); 104 | } 105 | 106 | } 107 | 108 | } 109 | 110 | -------------------------------------------------------------------------------- /mixer-transport/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate futures; 2 | extern crate futures_cpupool; 3 | extern crate protobuf; 4 | extern crate grpc; 5 | extern crate tls_api; 6 | extern crate time; 7 | extern crate base64; 8 | 9 | 10 | 11 | pub mod attribute; 12 | pub mod mixer_grpc; 13 | pub mod istio_client; 14 | pub mod transport; -------------------------------------------------------------------------------- /mixer-transport/src/mixer_grpc/.gitignore: -------------------------------------------------------------------------------- 1 | check.rs 2 | attributes.rs 3 | status.rs 4 | service_grpc.rs 5 | quota.rs 6 | report.rs 7 | -------------------------------------------------------------------------------- /mixer-transport/src/mixer_grpc/mod.rs: -------------------------------------------------------------------------------- 1 | extern crate protobuf; 2 | extern crate grpc; 3 | 4 | pub mod attributes; 5 | pub mod status; 6 | pub mod report; 7 | pub mod check; 8 | pub mod service_grpc; -------------------------------------------------------------------------------- /mixer-transport/src/transport/futures.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nginxinc/ngx-istio-mixer/0e3dfaaf2fc38c7a013404965b993a8afa5cc6c4/mixer-transport/src/transport/futures.rs -------------------------------------------------------------------------------- /mixer-transport/src/transport/mixer_grpc.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * mixer transport using grpc 3 | * returns future 4 | */ 5 | 6 | 7 | extern crate grpc; 8 | extern crate futures; 9 | 10 | 11 | use grpc::RequestOptions; 12 | use transport::server_info::MixerInfo; 13 | use transport::status:: { Status, StatusCodeEnum, from_int }; 14 | use mixer_grpc::service_grpc::MixerClient; 15 | use mixer_grpc::service_grpc::Mixer; 16 | use mixer_grpc::check:: { CheckRequest, CheckResponse }; 17 | use attribute::attr_wrapper::AttributeWrapper; 18 | use futures::future:: { Future,ok,err}; 19 | 20 | 21 | pub trait Transport { 22 | 23 | fn get_attributes(&self) -> &AttributeWrapper; 24 | 25 | fn check(&self,request: CheckRequest) -> Box> ; 26 | } 27 | 28 | 29 | 30 | pub struct GrpcTransport { 31 | 32 | mixer_info: MixerInfo, 33 | attributes: AttributeWrapper 34 | } 35 | 36 | impl GrpcTransport { 37 | 38 | pub fn new(info: MixerInfo, attributes: AttributeWrapper) -> GrpcTransport { 39 | GrpcTransport { 40 | mixer_info: info, 41 | attributes 42 | } 43 | } 44 | } 45 | 46 | impl Transport for GrpcTransport { 47 | 48 | 49 | fn get_attributes(&self) -> &AttributeWrapper { 50 | &self.attributes 51 | } 52 | 53 | fn check(&self,request: CheckRequest) -> Box> { 54 | 55 | let client = MixerClient::new_plain( self.mixer_info.get_server_name(), self.mixer_info.get_server_port() , Default::default()).expect("init"); 56 | let result = client.check(RequestOptions::new(), request).wait(); 57 | 58 | match result { 59 | Ok(response) => { 60 | let (_m1, check_response, _m2) = response; 61 | { 62 | //println!("received result check {:?}", check_response); 63 | 64 | let condition = check_response.get_precondition(); 65 | let status_code = condition.get_status(); 66 | // println!("received result condition {:?}", status_code); 67 | // println!("-------"); 68 | let status = from_int(status_code.get_code()); 69 | if status == StatusCodeEnum::PERMISSION_DENIED { 70 | return Box::new(err::(Status::with_code(StatusCodeEnum::PERMISSION_DENIED))) 71 | } 72 | } 73 | 74 | return Box::new(ok::(check_response)); 75 | }, 76 | 77 | Err(_error) => { 78 | // TODO: fix log error to nginx error logger 79 | // println!("error calling check {:?}", _error); 80 | return Box::new(err::(Status::with_code(StatusCodeEnum::CANCELLED))) 81 | } 82 | } 83 | 84 | 85 | } 86 | } 87 | 88 | -------------------------------------------------------------------------------- /mixer-transport/src/transport/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | pub mod mixer_grpc; 3 | pub mod status; 4 | pub mod server_info; 5 | 6 | #[cfg(test)] 7 | mod status_test; 8 | 9 | 10 | -------------------------------------------------------------------------------- /mixer-transport/src/transport/server_info.rs: -------------------------------------------------------------------------------- 1 | 2 | 3 | pub struct MixerInfo { 4 | pub server_name: String, 5 | pub server_port: u16, 6 | } 7 | 8 | 9 | impl MixerInfo { 10 | 11 | 12 | pub fn get_server_name(&self) -> &str { 13 | &self.server_name 14 | } 15 | 16 | pub fn get_server_port(&self) -> u16 { 17 | self.server_port 18 | } 19 | 20 | } 21 | 22 | -------------------------------------------------------------------------------- /mixer-transport/src/transport/status.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::mem; 3 | 4 | // https://github.com/google/protobuf/blob/master/src/google/protobuf/stubs/status.h 5 | 6 | #[allow(non_camel_case_types)] 7 | #[allow(dead_code)] 8 | #[derive(Debug, PartialEq, Copy, Clone)] 9 | pub enum StatusCodeEnum { 10 | 11 | OK = 0, 12 | CANCELLED = 1, 13 | UNKNOWN = 2, 14 | INVALID_ARGUMENT = 3, 15 | DEADLINE_EXCEEDED = 4, 16 | NOT_FOUND = 5, 17 | ALREADY_EXISTS = 6, 18 | PERMISSION_DENIED = 7, 19 | UNAUTHENTICATED = 16, 20 | RESOURCE_EXHAUSTED = 8, 21 | FAILED_PRECONDITION = 9, 22 | ABORTED = 10, 23 | OUT_OF_RANGE = 11, 24 | UNIMPLEMENTED = 12, 25 | INTERNAL = 13, 26 | UNAVAILABLE = 14, 27 | DATA_LOSS = 15, 28 | } 29 | 30 | 31 | // convert integer status to enum status 32 | pub fn from_int(code: i32) -> StatusCodeEnum { 33 | 34 | //return code as StatusCodeEnum; 35 | return unsafe { 36 | mem::transmute(code as u8) 37 | }; 38 | } 39 | 40 | #[derive(Clone, Debug)] 41 | pub struct Status { 42 | 43 | error_code: StatusCodeEnum, 44 | error_message: Option 45 | } 46 | 47 | impl Status { 48 | 49 | pub fn new() -> Status { 50 | Status { 51 | error_code: StatusCodeEnum::OK, 52 | error_message: None 53 | } 54 | } 55 | 56 | 57 | pub fn with_code( code: StatusCodeEnum) -> Status { 58 | Status { 59 | error_code: code, 60 | error_message: None 61 | } 62 | } 63 | 64 | pub fn with(error_code: StatusCodeEnum, error_message: String) -> Status { 65 | Status { 66 | error_code, 67 | error_message: Some(error_message) 68 | } 69 | } 70 | 71 | pub fn ok(&self) -> bool { 72 | self.error_code == StatusCodeEnum::OK 73 | } 74 | 75 | pub fn get_error_code(&self) -> StatusCodeEnum { 76 | self.error_code 77 | } 78 | } 79 | 80 | -------------------------------------------------------------------------------- /mixer-transport/src/transport/status_test.rs: -------------------------------------------------------------------------------- 1 | 2 | use super::status::{ Status, StatusCodeEnum }; 3 | 4 | 5 | #[test] 6 | fn test_code_ok() { 7 | 8 | let status = Status::new(); 9 | assert_eq!(status.get_error_code(), StatusCodeEnum::OK); 10 | } 11 | 12 | #[test] 13 | fn test_code_ok_invalid_arg() { 14 | 15 | let status = Status::with_code(StatusCodeEnum::INVALID_ARGUMENT); 16 | assert_eq!(status.get_error_code(), StatusCodeEnum::INVALID_ARGUMENT); 17 | } -------------------------------------------------------------------------------- /mixer-transport/tests/intg_transport_test.rs: -------------------------------------------------------------------------------- 1 | extern crate ngx_mixer_transport; 2 | extern crate grpc; 3 | extern crate futures; 4 | 5 | use std::collections::HashMap; 6 | use ngx_mixer_transport::istio_client::mixer_client_wrapper::MixerClientWrapper ; 7 | use ngx_mixer_transport::attribute::attr_wrapper::AttributeWrapper; 8 | use ngx_mixer_transport::transport::mixer_grpc::GrpcTransport; 9 | use ngx_mixer_transport::transport::server_info::MixerInfo; 10 | use ngx_mixer_transport::transport::status::{ StatusCodeEnum}; 11 | use futures::future::Future; 12 | 13 | // run integration test, in order to run this, mixer server should be running https://github.com/istio/mixer/blob/master/doc/dev/development.md 14 | // ./bazel-bin//cmd/server/mixs server --logtostderr --configStore2URL=fs://$(pwd)/testdata/config --configStoreURL=fs://$(pwd)/testdata/configroot -v=4 15 | 16 | 17 | #[test] 18 | fn intg_check_empty_request() { 19 | 20 | 21 | let info = MixerInfo { server_name: String::from("localhost"), server_port: 9091}; 22 | let attributes = AttributeWrapper::new(); 23 | 24 | let transport = GrpcTransport::new(info,attributes); 25 | 26 | let client = MixerClientWrapper::new(); 27 | 28 | let result = client.check(transport).wait(); 29 | 30 | println!("result, {:?}",result); 31 | 32 | match result { 33 | Ok(_) => assert!(true,"succeed"), 34 | Err(_) => assert!(false,"failed check") 35 | } 36 | } 37 | 38 | 39 | #[test] 40 | fn intg_check_deny() { 41 | 42 | 43 | let info = MixerInfo { server_name: String::from("localhost"), server_port: 9091}; 44 | let mut attributes = AttributeWrapper::new(); 45 | attributes.insert_string_attribute("destination.service","abc.ns.svc.cluster.local"); 46 | attributes.insert_string_attribute("source.name","myservice"); 47 | attributes.insert_string_attribute("source.port","8080"); 48 | 49 | let mut string_map: HashMap = HashMap::new(); 50 | string_map.insert("clnt".to_string(),"abc".to_string()); 51 | string_map.insert("source".to_string(),"abcd".to_string()); 52 | string_map.insert("destination.labels".to_string(),"app:ratings".to_string()); 53 | string_map.insert("labels".to_string(),"version:v2".to_string()); 54 | 55 | attributes.insert_string_map("request.headers",string_map); 56 | 57 | // --string_attributes destination.service=abc.ns.svc.cluster.local,source.name=myservice,target.port=8080 --stringmap_attributes "request.headers=clnt:abc;source:abcd,destination.labels=app:ratings,source.labels=version:v2" --timestamp_attributes request.time="2017-07-04T00:01:10Z" --bytes_attributes source.ip=c0:0:0:2 58 | //2017/10/31 15:21:18 grpc: addrConn.resetTrans 59 | 60 | let transport = GrpcTransport::new(info,attributes); 61 | 62 | let client = MixerClientWrapper::new(); 63 | 64 | let result = client.check(transport).wait(); 65 | 66 | println!("result, {:?}",result); 67 | 68 | match result { 69 | Ok(_) => assert!(false,"should not have succeed"), 70 | Err(error) => assert_eq!(error.get_error_code(),StatusCodeEnum::PERMISSION_DENIED,"permission denied expected") 71 | } 72 | } 73 | 74 | 75 | -------------------------------------------------------------------------------- /module/config: -------------------------------------------------------------------------------- 1 | ngx_addon_name=ngx_http_istio_mixer_module 2 | 3 | ngx_module_type=HTTP_FILTER 4 | ngx_module_name=ngx_http_istio_mixer_module 5 | ngx_module_srcs="$ngx_addon_dir/ngx_http_istio_mixer_module.c" 6 | ngx_module_deps="cargo" 7 | ngx_module_libs="$ngx_addon_dir/../target/release/libngx_mixer_module.a" 8 | 9 | 10 | . auto/module 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /module/config.make: -------------------------------------------------------------------------------- 1 | 2 | cat << END >> $NGX_MAKEFILE 3 | 4 | cargo: 5 | cargo build --release --manifest-path $ngx_addon_dir/../Cargo.toml --lib --all 6 | 7 | END 8 | -------------------------------------------------------------------------------- /module/release/ngx_http_istio_mixer_module.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nginxinc/ngx-istio-mixer/0e3dfaaf2fc38c7a013404965b993a8afa5cc6c4/module/release/ngx_http_istio_mixer_module.so -------------------------------------------------------------------------------- /nginx.mk: -------------------------------------------------------------------------------- 1 | NGINX_VER = 1.13.7 2 | RUST_COMPILER_TAG = 1.21.0 3 | DOCKER_REPO=nginmesh 4 | UNAME_S := $(shell uname -s) 5 | GIT_COMMIT=$(shell git rev-parse --short HEAD) 6 | NGX_DEBUG="--with-debug" 7 | export MODULE_DIR=${PWD} 8 | NGX_MODULES = --with-compat --with-threads --with-http_addition_module \ 9 | --with-http_auth_request_module --with-http_gunzip_module --with-http_gzip_static_module \ 10 | --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module \ 11 | --with-http_slice_module --with-http_stub_status_module --with-http_sub_module \ 12 | --with-stream --with-stream_realip_module --with-stream_ssl_preread_module 13 | ifeq ($(UNAME_S),Linux) 14 | NGINX_SRC += nginx-linux 15 | NGX_OPT= $(NGX_MODULES) \ 16 | --with-file-aio 17 | --with-cc-opt='-g -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' \ 18 | --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie' 19 | endif 20 | ifeq ($(UNAME_S),Darwin) 21 | NGINX_SRC += nginx-darwin 22 | NGX_OPT= $(NGX_MODULES) 23 | endif 24 | DOCKER_BUILD=./docker 25 | DOCKER_MODULE_IMAGE = $(DOCKER_REPO)/${MODULE_NAME} 26 | DOCKER_MODULE_BASE_IMAGE = $(DOCKER_REPO)/${MODULE_NAME}-base 27 | DOCKER_MODULE_NGINX_BUILD_IMAGE = $(DOCKER_REPO)/${MODULE_NAME}-ngx-build 28 | DOCKER_MODULE_NGINX_BASE_IMAGE= $(DOCKER_REPO)/${MODULE_NAME}-ngx-base 29 | DOCKER_RUST_IMAGE = $(DOCKER_REPO)/ngx-rust-tool:${RUST_COMPILER_TAG} 30 | DOCKER_NGIX_IMAGE = $(DOCKER_REPO)/nginx-dev:${NGINX_VER} 31 | DOCKER_MIXER_IMAGE = $(DOCKER_REPO)/ngix-mixer:1.0 32 | MODULE_SO_DIR=nginx/nginx-linux/objs 33 | MODULE_SO_BIN=${MODULE_SO_DIR}/${MODULE_NAME}.so 34 | NGINX_BIN=${MODULE_SO_DIR}/nginx 35 | MODULE_SO_HOST=module/release/${MODULE_NAME}.so 36 | NGINX_SO_HOST=config 37 | 38 | 39 | DOCKER_BUILD_TOOL=docker run -it --rm -v ${ROOT_DIR}:/src -w /src/${MODULE_PROJ_NAME} ${DOCKER_RUST_IMAGE} 40 | DOCKER_NGINX_TOOL=docker run -it --rm -v ${ROOT_DIR}:/src -w /src/${MODULE_PROJ_NAME} ${DOCKER_NGIX_IMAGE} 41 | DOCKER_NGINX_NAME=nginx-test 42 | DOCKER_NGINX_EXEC=docker exec -it ${DOCKER_NGINX_NAME} 43 | DOCKER_NGINX_EXECD=docker exec -d ${DOCKER_NGINX_NAME} 44 | DOCKER_NGINX_DAEMON=docker run -d -p 8000:8000 --privileged --name ${DOCKER_NGINX_NAME} \ 45 | --sysctl net.ipv4.ip_nonlocal_bind=1 \ 46 | --sysctl net.ipv4.ip_forward=1 \ 47 | -v ${MODULE_DIR}/module/release:/etc/nginx/modules \ 48 | -v ${MODULE_DIR}:/src -w /src ${DOCKER_NGIX_IMAGE} 49 | 50 | 51 | setup-nginx: 52 | mkdir -p nginx 53 | 54 | 55 | nginx-source: setup-nginx 56 | rm -rf nginx/${NGINX_SRC} 57 | wget http://nginx.org/download/nginx-${NGINX_VER}.tar.gz 58 | tar zxf nginx-${NGINX_VER}.tar.gz 59 | mv nginx-${NGINX_VER} ${NGINX_SRC} 60 | mv ${NGINX_SRC} nginx 61 | rm nginx-${NGINX_VER}.tar.gz* 62 | 63 | nginx-configure: 64 | cd nginx/${NGINX_SRC}; \ 65 | ./configure --add-dynamic-module=../../module $(NGX_OPT) 66 | 67 | 68 | nginx-setup: nginx-source nginx-configure 69 | 70 | 71 | nginx-module: 72 | cd nginx/${NGINX_SRC}; \ 73 | make modules; \ 74 | strip objs/*.so 75 | 76 | 77 | 78 | copy-module: 79 | docker rm -v ngx-copy || true 80 | docker create --name ngx-copy ${DOCKER_MODULE_IMAGE}:latest 81 | docker cp ngx-copy:/src/${MODULE_SO_BIN} ${MODULE_SO_HOST} 82 | docker rm -v ngx-copy 83 | 84 | # build module using docker 85 | # we copy only necessary context to docker daemon (src and module directory) 86 | build-module-docker: 87 | rm -rf $(DOCKER_BUILD)/context 88 | mkdir $(DOCKER_BUILD)/context 89 | cp $(DOCKER_BUILD)/Dockerfile.module $(DOCKER_BUILD)/context 90 | cp -r mixer-ngx $(DOCKER_BUILD)/context 91 | cp -r mixer-transport $(DOCKER_BUILD)/context 92 | cp -r mixer-tests $(DOCKER_BUILD)/context 93 | cp -r module $(DOCKER_BUILD)/context 94 | docker build -f $(DOCKER_BUILD)/context/Dockerfile.module -t ${DOCKER_MODULE_IMAGE}:latest $(DOCKER_BUILD)/context 95 | 96 | # build module and deposit in the module directory 97 | build-module: build-module-docker copy-module 98 | 99 | # build base container image that pre-compiles rust and nginx modules 100 | build-base: 101 | docker build -f $(DOCKER_BUILD)/Dockerfile.base -t ${DOCKER_MODULE_BASE_IMAGE}:${GIT_COMMIT} . 102 | docker tag ${DOCKER_MODULE_BASE_IMAGE}:${GIT_COMMIT} ${DOCKER_MODULE_BASE_IMAGE}:latest 103 | 104 | 105 | run-base-image: 106 | docker run -it --rm ${DOCKER_MODULE_BASE_IMAGE}:latest /bin/bash 107 | 108 | 109 | run-module-image: 110 | docker run -it --rm ${DOCKER_MODULE_IMAGE}:latest /bin/bash 111 | 112 | 113 | 114 | watch-mixer: 115 | kubectl logs -f $(kubectl get pod -l istio=mixer -n istio-system -o jsonpath='{.items[0].metadata.name}') -n istio-system -c mixer 116 | 117 | 118 | 119 | 120 | # setup nginx container for testing 121 | # copies the configuration and modules 122 | # start test services 123 | test-nginx-setup: 124 | test/deploy.sh 125 | 126 | 127 | # run integrated test 128 | test-intg: 129 | cargo +stable test --color=always intg -- --nocapture 130 | 131 | 132 | test-unit: 133 | cargo test --lib 134 | 135 | 136 | # remove nginx container 137 | test-nginx-clean: 138 | docker rm -f ${DOCKER_NGINX_NAME} || true 139 | 140 | 141 | test-nginx-only: test-nginx-clean 142 | $(DOCKER_NGINX_DAEMON) 143 | $(DOCKER_NGINX_EXECD) make test-nginx-setup > make.out 144 | sleep 1 145 | 146 | 147 | test-nginx-log: 148 | docker logs -f nginx-test 149 | 150 | 151 | test-nginx-full: build-module test-nginx-only 152 | 153 | # invoke http service 154 | test-http: 155 | curl localhost:8000 -------------------------------------------------------------------------------- /protobuf/gogoproto/gogo.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Go with Gadgets 2 | // 3 | // Copyright (c) 2013, The GoGo Authors. All rights reserved. 4 | // http://github.com/gogo/protobuf 5 | // 6 | // Redistribution and use in source and binary forms, with or without 7 | // modification, are permitted provided that the following conditions are 8 | // met: 9 | // 10 | // * Redistributions of source code must retain the above copyright 11 | // notice, this list of conditions and the following disclaimer. 12 | // * Redistributions in binary form must reproduce the above 13 | // copyright notice, this list of conditions and the following disclaimer 14 | // in the documentation and/or other materials provided with the 15 | // distribution. 16 | // 17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | syntax = "proto2"; 30 | package gogoproto; 31 | 32 | import "google/protobuf/descriptor.proto"; 33 | 34 | option java_package = "com.google.local"; 35 | option java_outer_classname = "GoGoProtos"; 36 | 37 | extend google.protobuf.EnumOptions { 38 | optional bool goproto_enum_prefix = 62001; 39 | optional bool goproto_enum_stringer = 62021; 40 | optional bool enum_stringer = 62022; 41 | optional string enum_customname = 62023; 42 | optional bool enumdecl = 62024; 43 | } 44 | 45 | extend google.protobuf.EnumValueOptions { 46 | optional string enumvalue_customname = 66001; 47 | } 48 | 49 | extend google.protobuf.FileOptions { 50 | optional bool goproto_getters_all = 63001; 51 | optional bool goproto_enum_prefix_all = 63002; 52 | optional bool goproto_stringer_all = 63003; 53 | optional bool verbose_equal_all = 63004; 54 | optional bool face_all = 63005; 55 | optional bool gostring_all = 63006; 56 | optional bool populate_all = 63007; 57 | optional bool stringer_all = 63008; 58 | optional bool onlyone_all = 63009; 59 | 60 | optional bool equal_all = 63013; 61 | optional bool description_all = 63014; 62 | optional bool testgen_all = 63015; 63 | optional bool benchgen_all = 63016; 64 | optional bool marshaler_all = 63017; 65 | optional bool unmarshaler_all = 63018; 66 | optional bool stable_marshaler_all = 63019; 67 | 68 | optional bool sizer_all = 63020; 69 | 70 | optional bool goproto_enum_stringer_all = 63021; 71 | optional bool enum_stringer_all = 63022; 72 | 73 | optional bool unsafe_marshaler_all = 63023; 74 | optional bool unsafe_unmarshaler_all = 63024; 75 | 76 | optional bool goproto_extensions_map_all = 63025; 77 | optional bool goproto_unrecognized_all = 63026; 78 | optional bool gogoproto_import = 63027; 79 | optional bool protosizer_all = 63028; 80 | optional bool compare_all = 63029; 81 | optional bool typedecl_all = 63030; 82 | optional bool enumdecl_all = 63031; 83 | 84 | optional bool goproto_registration = 63032; 85 | } 86 | 87 | extend google.protobuf.MessageOptions { 88 | optional bool goproto_getters = 64001; 89 | optional bool goproto_stringer = 64003; 90 | optional bool verbose_equal = 64004; 91 | optional bool face = 64005; 92 | optional bool gostring = 64006; 93 | optional bool populate = 64007; 94 | optional bool stringer = 67008; 95 | optional bool onlyone = 64009; 96 | 97 | optional bool equal = 64013; 98 | optional bool description = 64014; 99 | optional bool testgen = 64015; 100 | optional bool benchgen = 64016; 101 | optional bool marshaler = 64017; 102 | optional bool unmarshaler = 64018; 103 | optional bool stable_marshaler = 64019; 104 | 105 | optional bool sizer = 64020; 106 | 107 | optional bool unsafe_marshaler = 64023; 108 | optional bool unsafe_unmarshaler = 64024; 109 | 110 | optional bool goproto_extensions_map = 64025; 111 | optional bool goproto_unrecognized = 64026; 112 | 113 | optional bool protosizer = 64028; 114 | optional bool compare = 64029; 115 | 116 | optional bool typedecl = 64030; 117 | } 118 | 119 | extend google.protobuf.FieldOptions { 120 | optional bool nullable = 65001; 121 | optional bool embed = 65002; 122 | optional string customtype = 65003; 123 | optional string customname = 65004; 124 | optional string jsontag = 65005; 125 | optional string moretags = 65006; 126 | optional string casttype = 65007; 127 | optional string castkey = 65008; 128 | optional string castvalue = 65009; 129 | 130 | optional bool stdtime = 65010; 131 | optional bool stdduration = 65011; 132 | } 133 | -------------------------------------------------------------------------------- /protobuf/google/protobuf/any.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option go_package = "github.com/golang/protobuf/ptypes/any"; 37 | option java_package = "com.google.local"; 38 | option java_outer_classname = "AnyProto"; 39 | option java_multiple_files = true; 40 | option objc_class_prefix = "GPB"; 41 | 42 | // `Any` contains an arbitrary serialized protocol buffer message along with a 43 | // URL that describes the type of the serialized message. 44 | // 45 | // Protobuf library provides support to pack/unpack Any values in the form 46 | // of utility functions or additional generated methods of the Any type. 47 | // 48 | // Example 1: Pack and unpack a message in C++. 49 | // 50 | // Foo foo = ...; 51 | // Any any; 52 | // any.PackFrom(foo); 53 | // ... 54 | // if (any.UnpackTo(&foo)) { 55 | // ... 56 | // } 57 | // 58 | // Example 2: Pack and unpack a message in Java. 59 | // 60 | // Foo foo = ...; 61 | // Any any = Any.pack(foo); 62 | // ... 63 | // if (any.is(Foo.class)) { 64 | // foo = any.unpack(Foo.class); 65 | // } 66 | // 67 | // Example 3: Pack and unpack a message in Python. 68 | // 69 | // foo = Foo(...) 70 | // any = Any() 71 | // any.Pack(foo) 72 | // ... 73 | // if any.Is(Foo.DESCRIPTOR): 74 | // any.Unpack(foo) 75 | // ... 76 | // 77 | // The pack methods provided by protobuf library will by default use 78 | // 'type.googleapis.com/full.type.name' as the type URL and the unpack 79 | // methods only use the fully qualified type name after the last '/' 80 | // in the type URL, for example "foo.bar.com/x/y.z" will yield type 81 | // name "y.z". 82 | // 83 | // 84 | // JSON 85 | // ==== 86 | // The JSON representation of an `Any` value uses the regular 87 | // representation of the deserialized, embedded message, with an 88 | // additional field `@type` which contains the type URL. Example: 89 | // 90 | // package google.profile; 91 | // message Person { 92 | // string first_name = 1; 93 | // string last_name = 2; 94 | // } 95 | // 96 | // { 97 | // "@type": "type.googleapis.com/google.profile.Person", 98 | // "firstName": , 99 | // "lastName": 100 | // } 101 | // 102 | // If the embedded message type is well-known and has a custom JSON 103 | // representation, that representation will be embedded adding a field 104 | // `value` which holds the custom JSON in addition to the `@type` 105 | // field. Example (for message [google.protobuf.Duration][]): 106 | // 107 | // { 108 | // "@type": "type.googleapis.com/google.protobuf.Duration", 109 | // "value": "1.212s" 110 | // } 111 | // 112 | message Any { 113 | // A URL/resource name whose content describes the type of the 114 | // serialized protocol buffer message. 115 | // 116 | // For URLs which use the scheme `http`, `https`, or no scheme, the 117 | // following restrictions and interpretations apply: 118 | // 119 | // * If no scheme is provided, `https` is assumed. 120 | // * The last segment of the URL's path must represent the fully 121 | // qualified name of the type (as in `path/google.protobuf.Duration`). 122 | // The name should be in a canonical form (e.g., leading "." is 123 | // not accepted). 124 | // * An HTTP GET on the URL must yield a [google.protobuf.Type][] 125 | // value in binary format, or produce an error. 126 | // * Applications are allowed to cache lookup results based on the 127 | // URL, or have them precompiled into a binary to avoid any 128 | // lookup. Therefore, binary compatibility needs to be preserved 129 | // on changes to types. (Use versioned type names to manage 130 | // breaking changes.) 131 | // 132 | // Schemes other than `http`, `https` (or the empty scheme) might be 133 | // used with implementation specific semantics. 134 | // 135 | string type_url = 1; 136 | 137 | // Must be a valid serialized protocol buffer of the above specified type. 138 | bytes value = 2; 139 | } 140 | -------------------------------------------------------------------------------- /protobuf/google/protobuf/duration.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option cc_enable_arenas = true; 37 | option go_package = "github.com/golang/protobuf/ptypes/duration"; 38 | option java_package = "com.google.local"; 39 | option java_outer_classname = "DurationProto"; 40 | option java_multiple_files = true; 41 | option objc_class_prefix = "GPB"; 42 | 43 | // A Duration represents a signed, fixed-length span of time represented 44 | // as a count of seconds and fractions of seconds at nanosecond 45 | // resolution. It is independent of any calendar and concepts like "day" 46 | // or "month". It is related to Timestamp in that the difference between 47 | // two Timestamp values is a Duration and it can be added or subtracted 48 | // from a Timestamp. Range is approximately +-10,000 years. 49 | // 50 | // # Examples 51 | // 52 | // Example 1: Compute Duration from two Timestamps in pseudo code. 53 | // 54 | // Timestamp start = ...; 55 | // Timestamp end = ...; 56 | // Duration duration = ...; 57 | // 58 | // duration.seconds = end.seconds - start.seconds; 59 | // duration.nanos = end.nanos - start.nanos; 60 | // 61 | // if (duration.seconds < 0 && duration.nanos > 0) { 62 | // duration.seconds += 1; 63 | // duration.nanos -= 1000000000; 64 | // } else if (durations.seconds > 0 && duration.nanos < 0) { 65 | // duration.seconds -= 1; 66 | // duration.nanos += 1000000000; 67 | // } 68 | // 69 | // Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. 70 | // 71 | // Timestamp start = ...; 72 | // Duration duration = ...; 73 | // Timestamp end = ...; 74 | // 75 | // end.seconds = start.seconds + duration.seconds; 76 | // end.nanos = start.nanos + duration.nanos; 77 | // 78 | // if (end.nanos < 0) { 79 | // end.seconds -= 1; 80 | // end.nanos += 1000000000; 81 | // } else if (end.nanos >= 1000000000) { 82 | // end.seconds += 1; 83 | // end.nanos -= 1000000000; 84 | // } 85 | // 86 | // Example 3: Compute Duration from datetime.timedelta in Python. 87 | // 88 | // td = datetime.timedelta(days=3, minutes=10) 89 | // duration = Duration() 90 | // duration.FromTimedelta(td) 91 | // 92 | // # JSON Mapping 93 | // 94 | // In JSON format, the Duration type is encoded as a string rather than an 95 | // object, where the string ends in the suffix "s" (indicating seconds) and 96 | // is preceded by the number of seconds, with nanoseconds expressed as 97 | // fractional seconds. For example, 3 seconds with 0 nanoseconds should be 98 | // encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should 99 | // be expressed in JSON format as "3.000000001s", and 3 seconds and 1 100 | // microsecond should be expressed in JSON format as "3.000001s". 101 | // 102 | // 103 | message Duration { 104 | 105 | // Signed seconds of the span of time. Must be from -315,576,000,000 106 | // to +315,576,000,000 inclusive. Note: these bounds are computed from: 107 | // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years 108 | int64 seconds = 1; 109 | 110 | // Signed fractions of a second at nanosecond resolution of the span 111 | // of time. Durations less than one second are represented with a 0 112 | // `seconds` field and a positive or negative `nanos` field. For durations 113 | // of one second or more, a non-zero value for the `nanos` field must be 114 | // of the same sign as the `seconds` field. Must be from -999,999,999 115 | // to +999,999,999 inclusive. 116 | int32 nanos = 2; 117 | } 118 | -------------------------------------------------------------------------------- /protobuf/google/protobuf/timestamp.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option cc_enable_arenas = true; 37 | option go_package = "github.com/golang/protobuf/ptypes/timestamp"; 38 | option java_package = "com.google.local"; 39 | option java_outer_classname = "TimestampProto"; 40 | option java_multiple_files = true; 41 | option objc_class_prefix = "GPB"; 42 | 43 | // A Timestamp represents a point in time independent of any time zone 44 | // or calendar, represented as seconds and fractions of seconds at 45 | // nanosecond resolution in UTC Epoch time. It is encoded using the 46 | // Proleptic Gregorian Calendar which extends the Gregorian calendar 47 | // backwards to year one. It is encoded assuming all minutes are 60 48 | // seconds long, i.e. leap seconds are "smeared" so that no leap second 49 | // table is needed for interpretation. Range is from 50 | // 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. 51 | // By restricting to that range, we ensure that we can convert to 52 | // and from RFC 3339 date strings. 53 | // See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt). 54 | // 55 | // # Examples 56 | // 57 | // Example 1: Compute Timestamp from POSIX `time()`. 58 | // 59 | // Timestamp timestamp; 60 | // timestamp.set_seconds(time(NULL)); 61 | // timestamp.set_nanos(0); 62 | // 63 | // Example 2: Compute Timestamp from POSIX `gettimeofday()`. 64 | // 65 | // struct timeval tv; 66 | // gettimeofday(&tv, NULL); 67 | // 68 | // Timestamp timestamp; 69 | // timestamp.set_seconds(tv.tv_sec); 70 | // timestamp.set_nanos(tv.tv_usec * 1000); 71 | // 72 | // Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. 73 | // 74 | // FILETIME ft; 75 | // GetSystemTimeAsFileTime(&ft); 76 | // UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; 77 | // 78 | // // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z 79 | // // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. 80 | // Timestamp timestamp; 81 | // timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); 82 | // timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); 83 | // 84 | // Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. 85 | // 86 | // long millis = System.currentTimeMillis(); 87 | // 88 | // Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) 89 | // .setNanos((int) ((millis % 1000) * 1000000)).build(); 90 | // 91 | // 92 | // Example 5: Compute Timestamp from current time in Python. 93 | // 94 | // timestamp = Timestamp() 95 | // timestamp.GetCurrentTime() 96 | // 97 | // # JSON Mapping 98 | // 99 | // In JSON format, the Timestamp type is encoded as a string in the 100 | // [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the 101 | // format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" 102 | // where {year} is always expressed using four digits while {month}, {day}, 103 | // {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional 104 | // seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), 105 | // are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone 106 | // is required, though only UTC (as indicated by "Z") is presently supported. 107 | // 108 | // For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 109 | // 01:30 UTC on January 15, 2017. 110 | // 111 | // In JavaScript, one can convert a Date object to this format using the 112 | // standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString] 113 | // method. In Python, a standard `datetime.datetime` object can be converted 114 | // to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) 115 | // with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one 116 | // can use the Joda Time's [`ISODateTimeFormat.dateTime()`]( 117 | // http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()) 118 | // to obtain a formatter capable of generating timestamps in this format. 119 | // 120 | // 121 | message Timestamp { 122 | 123 | // Represents seconds of UTC time since Unix epoch 124 | // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to 125 | // 9999-12-31T23:59:59Z inclusive. 126 | int64 seconds = 1; 127 | 128 | // Non-negative fractions of a second at nanosecond resolution. Negative 129 | // second values with fractions must still have non-negative nanos values 130 | // that count forward in time. Must be from 0 to 999,999,999 131 | // inclusive. 132 | int32 nanos = 2; 133 | } 134 | -------------------------------------------------------------------------------- /protobuf/google/rpc/status.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package google.rpc; 18 | 19 | import "google/protobuf/any.proto"; 20 | 21 | option go_package = "google.golang.org/genproto/googleapis/rpc/status;status"; 22 | option java_multiple_files = true; 23 | option java_outer_classname = "StatusProto"; 24 | option java_package = "com.google.rpc"; 25 | option objc_class_prefix = "RPC"; 26 | 27 | 28 | // The `Status` type defines a logical error model that is suitable for different 29 | // programming environments, including REST APIs and RPC APIs. It is used by 30 | // [gRPC](https://github.com/grpc). The error model is designed to be: 31 | // 32 | // - Simple to use and understand for most users 33 | // - Flexible enough to meet unexpected needs 34 | // 35 | // # Overview 36 | // 37 | // The `Status` message contains three pieces of data: error code, error message, 38 | // and error details. The error code should be an enum value of 39 | // [google.rpc.Code][google.rpc.Code], but it may accept additional error codes if needed. The 40 | // error message should be a developer-facing English message that helps 41 | // developers *understand* and *resolve* the error. If a localized user-facing 42 | // error message is needed, put the localized message in the error details or 43 | // localize it in the client. The optional error details may contain arbitrary 44 | // information about the error. There is a predefined set of error detail types 45 | // in the package `google.rpc` which can be used for common error conditions. 46 | // 47 | // # Language mapping 48 | // 49 | // The `Status` message is the logical representation of the error model, but it 50 | // is not necessarily the actual wire format. When the `Status` message is 51 | // exposed in different client libraries and different wire protocols, it can be 52 | // mapped differently. For example, it will likely be mapped to some exceptions 53 | // in Java, but more likely mapped to some error codes in C. 54 | // 55 | // # Other uses 56 | // 57 | // The error model and the `Status` message can be used in a variety of 58 | // environments, either with or without APIs, to provide a 59 | // consistent developer experience across different environments. 60 | // 61 | // Example uses of this error model include: 62 | // 63 | // - Partial errors. If a service needs to return partial errors to the client, 64 | // it may embed the `Status` in the normal response to indicate the partial 65 | // errors. 66 | // 67 | // - Workflow errors. A typical workflow has multiple steps. Each step may 68 | // have a `Status` message for error reporting purpose. 69 | // 70 | // - Batch operations. If a client uses batch request and batch response, the 71 | // `Status` message should be used directly inside batch response, one for 72 | // each error sub-response. 73 | // 74 | // - Asynchronous operations. If an API call embeds asynchronous operation 75 | // results in its response, the status of those operations should be 76 | // represented directly using the `Status` message. 77 | // 78 | // - Logging. If some API errors are stored in logs, the message `Status` could 79 | // be used directly after any stripping needed for security/privacy reasons. 80 | message Status { 81 | // The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. 82 | int32 code = 1; 83 | 84 | // A developer-facing error message, which should be in English. Any 85 | // user-facing error message should be localized and sent in the 86 | // [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. 87 | string message = 2; 88 | 89 | // A list of messages that carry the error details. There will be a 90 | // common set of message types for APIs to use. 91 | repeated google.protobuf.Any details = 3; 92 | } 93 | -------------------------------------------------------------------------------- /protobuf/mixer/v1/attributes.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Istio Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package istio.mixer.v1; 18 | 19 | option go_package = "istio.io/api/mixer/v1"; 20 | 21 | import "gogoproto/gogo.proto"; 22 | import "google/protobuf/duration.proto"; 23 | import "google/protobuf/timestamp.proto"; 24 | 25 | option (gogoproto.goproto_getters_all) = false; 26 | option (gogoproto.equal_all) = false; 27 | option (gogoproto.gostring_all) = false; 28 | 29 | // Attributes represents a set of typed name/value pairs. Many of Mixer's 30 | // API either consume and/or return attributes. 31 | // 32 | // Istio uses attributes to control the runtime behavior of services running in the service mesh. 33 | // Attributes are named and typed pieces of metadata describing ingress and egress traffic and the 34 | // environment this traffic occurs in. An Istio attribute carries a specific piece 35 | // of information such as the error code of an API request, the latency of an API request, or the 36 | // original IP address of a TCP connection. For example: 37 | // 38 | // ``` 39 | // request.path: xyz/abc 40 | // request.size: 234 41 | // request.time: 12:34:56.789 04/17/2017 42 | // source.ip: 192.168.0.1 43 | // target.service: example 44 | // ``` 45 | // 46 | // A given Istio deployment has a fixed vocabulary of attributes that it understands. 47 | // The specific vocabulary is determined by the set of attribute producers being used 48 | // in the deployment. The primary attribute producer in Istio is Envoy, although 49 | // specialized Mixer adapters and services can also generate attributes. 50 | // 51 | // The common baseline set of attributes available in most Istio deployments is defined 52 | // [here](https://istio.io/docs/reference/config/mixer/attribute-vocabulary.html). 53 | // 54 | // Attributes are strongly typed. The supported attribute types are defined by 55 | // [ValueType](https://github.com/istio/api/blob/master/policy/v1beta1/value_type.proto). 56 | // Each type of value is encoded into one of the so-called transport types present 57 | // in this message. 58 | // 59 | // Defines a map of attributes in uncompressed format. 60 | // Following places may use this message: 61 | // 1) Configure Istio/Proxy with static per-proxy attributes, such as source.uid. 62 | // 2) Service IDL definition to extract api attributes for active requests. 63 | // 3) Forward attributes from client proxy to server proxy for HTTP requests. 64 | message Attributes { 65 | // A map of attribute name to its value. 66 | map attributes = 1; 67 | 68 | // Specifies one attribute value with different type. 69 | message AttributeValue { 70 | // The attribute value. 71 | oneof value { 72 | // Used for values of type STRING, DNS_NAME, EMAIL_ADDRESS, and URI 73 | string string_value = 2; 74 | 75 | // Used for values of type INT64 76 | int64 int64_value = 3; 77 | 78 | // Used for values of type DOUBLE 79 | double double_value = 4; 80 | 81 | // Used for values of type BOOL 82 | bool bool_value = 5; 83 | 84 | // Used for values of type BYTES 85 | bytes bytes_value = 6; 86 | 87 | // Used for values of type TIMESTAMP 88 | google.protobuf.Timestamp timestamp_value = 7; 89 | 90 | // Used for values of type DURATION 91 | google.protobuf.Duration duration_value = 8; 92 | 93 | // Used for values of type STRING_MAP 94 | StringMap string_map_value = 9; 95 | } 96 | } 97 | 98 | // Defines a string map. 99 | message StringMap { 100 | // Holds a set of name/value pairs. 101 | map entries = 1; 102 | } 103 | } 104 | 105 | // Defines a list of attributes in compressed format optimized for transport. 106 | // Within this message, strings are referenced using integer indices into 107 | // one of two string dictionaries. Positive integers index into the global 108 | // deployment-wide dictionary, whereas negative integers index into the message-level 109 | // dictionary instead. The message-level dictionary is carried by the 110 | // `words` field of this message, the deployment-wide dictionary is determined via 111 | // configuration. 112 | message CompressedAttributes { 113 | // The message-level dictionary. 114 | repeated string words = 1; 115 | 116 | // Holds attributes of type STRING, DNS_NAME, EMAIL_ADDRESS, URI 117 | map strings = 2; 118 | 119 | // Holds attributes of type INT64 120 | map int64s = 3; 121 | 122 | // Holds attributes of type DOUBLE 123 | map doubles = 4; 124 | 125 | // Holds attributes of type BOOL 126 | map bools = 5; 127 | 128 | // Holds attributes of type TIMESTAMP 129 | map timestamps = 6 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; 130 | 131 | // Holds attributes of type DURATION 132 | map durations = 7 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; 133 | 134 | // Holds attributes of type BYTES 135 | map bytes = 8; 136 | 137 | // Holds attributes of type STRING_MAP 138 | map string_maps = 9 [(gogoproto.nullable) = false]; 139 | } 140 | 141 | // A map of string to string. The keys and values in this map are dictionary 142 | // indices (see the [Attributes][istio.mixer.v1.CompressedAttributes] message for an explanation) 143 | message StringMap { 144 | // Holds a set of name/value pairs. 145 | map entries = 1; 146 | } 147 | -------------------------------------------------------------------------------- /protobuf/mixer/v1/check.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Istio Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package istio.mixer.v1; 18 | 19 | option go_package = "istio.io/api/mixer/v1"; 20 | 21 | import "gogoproto/gogo.proto"; 22 | import "google/protobuf/duration.proto"; 23 | import "google/rpc/status.proto"; 24 | import "mixer/v1/attributes.proto"; 25 | 26 | option (gogoproto.goproto_getters_all) = false; 27 | option (gogoproto.equal_all) = false; 28 | option (gogoproto.gostring_all) = false; 29 | 30 | // Used to get a thumbs-up/thumbs-down before performing an action. 31 | message CheckRequest { 32 | // parameters for a quota allocation 33 | message QuotaParams { 34 | // Amount of quota to allocate 35 | int64 amount = 1; 36 | 37 | // When true, supports returning less quota than what was requested. 38 | bool best_effort = 2; 39 | } 40 | 41 | // The attributes to use for this request. 42 | // 43 | // Mixer's configuration determines how these attributes are used to 44 | // establish the result returned in the response. 45 | CompressedAttributes attributes = 1 [(gogoproto.nullable) = false]; 46 | 47 | // The number of words in the global dictionary, used with to populate the attributes. 48 | // This value is used as a quick way to determine whether the client is using a dictionary that 49 | // the server understands. 50 | uint32 global_word_count = 2; 51 | 52 | // Used for deduplicating `Check` calls in the case of failed RPCs and retries. This should be a UUID 53 | // per call, where the same UUID is used for retries of the same call. 54 | string deduplication_id = 3; 55 | 56 | // The individual quotas to allocate 57 | map quotas = 4 [(gogoproto.nullable) = false]; 58 | } 59 | 60 | // The response generated by the Check method. 61 | message CheckResponse { 62 | // Expresses the result of a precondition check. 63 | message PreconditionResult { 64 | // A status code of OK indicates all preconditions were satisfied. Any other code indicates not 65 | // all preconditions were satisfied and details describe why. 66 | google.rpc.Status status = 1 [(gogoproto.nullable) = false]; 67 | 68 | // The amount of time for which this result can be considered valid. 69 | google.protobuf.Duration valid_duration = 2 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; 70 | 71 | // The number of uses for which this result can be considered valid. 72 | int32 valid_use_count = 3; 73 | 74 | // The attributes returned by Mixer. 75 | // 76 | // The exact set of attributes returned is determined by the set of 77 | // adapters Mixer is configured with. These attributes are used to 78 | // ferry new attributes that Mixer derived based on the input set of 79 | // attributes and its configuration. 80 | CompressedAttributes attributes = 4 [(gogoproto.nullable) = false]; 81 | 82 | // The total set of attributes that were used in producing the result 83 | // along with matching conditions. 84 | ReferencedAttributes referenced_attributes = 5 [(gogoproto.nullable) = false]; 85 | } 86 | 87 | // Expresses the result of a quota allocation. 88 | message QuotaResult { 89 | // The amount of time for which this result can be considered valid. 90 | google.protobuf.Duration valid_duration = 1 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; 91 | 92 | // The amount of granted quota. When `QuotaParams.best_effort` is true, this will be >= 0. 93 | // If `QuotaParams.best_effort` is false, this will be either 0 or >= `QuotaParams.amount`. 94 | int64 granted_amount = 2; 95 | 96 | // The total set of attributes that were used in producing the result 97 | // along with matching conditions. 98 | ReferencedAttributes referenced_attributes = 5 [(gogoproto.nullable) = false]; 99 | } 100 | 101 | // The precondition check results. 102 | PreconditionResult precondition = 2 [(gogoproto.nullable) = false]; 103 | 104 | // The resulting quota, one entry per requested quota. 105 | map quotas = 3 [(gogoproto.nullable) = false]; 106 | } 107 | 108 | // Describes the attributes that were used to determine the response. 109 | // This can be used to construct a response cache. 110 | message ReferencedAttributes { 111 | // How an attribute's value was matched 112 | enum Condition { 113 | CONDITION_UNSPECIFIED = 0; // should not occur 114 | ABSENCE = 1; // match when attribute doesn't exist 115 | EXACT = 2; // match when attribute value is an exact byte-for-byte match 116 | REGEX = 3; // match when attribute value matches the included regex 117 | } 118 | 119 | // Describes a single attribute match. 120 | message AttributeMatch { 121 | // The name of the attribute. This is a dictionary index encoded in a manner identical 122 | // to all strings in the [CompressedAttributes][istio.mixer.v1.CompressedAttributes] message. 123 | sint32 name = 1; 124 | 125 | // The kind of match against the attribute value. 126 | Condition condition = 2; 127 | 128 | // If a REGEX condition is provided for a STRING_MAP attribute, 129 | // clients should use the regex value to match against map keys. 130 | string regex = 3; 131 | 132 | // A key in a STRING_MAP. When multiple keys from a STRING_MAP 133 | // attribute were referenced, there will be multiple AttributeMatch 134 | // messages with different map_key values. Values for map_key SHOULD 135 | // be ignored for attributes that are not STRING_MAP. 136 | // 137 | // Indices for the keys are used (taken either from the 138 | // message dictionary from the `words` field or the global dictionary). 139 | // 140 | // If no map_key value is provided for a STRING_MAP attribute, the 141 | // entire STRING_MAP will be used. 142 | sint32 map_key = 4; 143 | } 144 | 145 | // The message-level dictionary. Refer to [CompressedAttributes][istio.mixer.v1.CompressedAttributes] for information 146 | // on using dictionaries. 147 | repeated string words = 1; 148 | 149 | // Describes a set of attributes. 150 | repeated AttributeMatch attribute_matches = 2 [(gogoproto.nullable) = false]; 151 | } 152 | -------------------------------------------------------------------------------- /protobuf/mixer/v1/config/client/api_spec.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Istio Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package istio.mixer.v1.config.client; 18 | 19 | option go_package="istio.io/api/mixer/v1/config/client"; 20 | 21 | import "gogoproto/gogo.proto"; 22 | 23 | import "mixer/v1/attributes.proto"; 24 | import "mixer/v1/config/client/service.proto"; 25 | 26 | option (gogoproto.goproto_getters_all) = false; 27 | option (gogoproto.equal_all) = false; 28 | option (gogoproto.gostring_all) = false; 29 | 30 | // HTTPAPISpec defines the canonical configuration for generating 31 | // API-related attributes from HTTP requests based on the method and 32 | // uri templated path matches. It is sufficient for defining the API 33 | // surface of a service for the purposes of API attribute 34 | // generation. It is not intended to represent auth, quota, 35 | // documentation, or other information commonly found in other API 36 | // specifications, e.g. OpenAPI. 37 | // 38 | // Existing standards that define operations (or methods) in terms of 39 | // HTTP methods and paths can be normalized to this format for use in 40 | // Istio. For example, a simple petstore API described by OpenAPIv2 41 | // [here](https://github.com/googleapis/gnostic/blob/master/examples/v2.0/yaml/petstore-simple.yaml) 42 | // can be represented with the following HTTPAPISpec. 43 | // 44 | // apiVersion: config.istio.io/v1alpha2 45 | // kind: HTTPAPISpec 46 | // metadata: 47 | // name: petstore 48 | // namespace: default 49 | // spec: 50 | // attributes: 51 | // api.service: petstore.swagger.io 52 | // api.version: 1.0.0 53 | // patterns: 54 | // - attributes: 55 | // api.operation: findPets 56 | // httpMethod: GET 57 | // uriTemplate: /api/pets 58 | // - attributes: 59 | // api.operation: addPet 60 | // httpMethod: POST 61 | // uriTemplate: /api/pets 62 | // - attributes: 63 | // api.operation: findPetById 64 | // httpMethod: GET 65 | // uriTemplate: /api/pets/{id} 66 | // - attributes: 67 | // api.operation: deletePet 68 | // httpMethod: DELETE 69 | // uriTemplate: /api/pets/{id} 70 | // api_keys: 71 | // - query: api-key 72 | // 73 | message HTTPAPISpec { 74 | // List of attributes that are generated when *any* of the HTTP 75 | // patterns match. This list typically includes the "api.service" 76 | // and "api.version" attributes. 77 | Attributes attributes = 1; 78 | 79 | // List of HTTP patterns to match. 80 | repeated HTTPAPISpecPattern patterns = 2; 81 | 82 | // List of APIKey that describes how to extract an API-KEY from an 83 | // HTTP request. The first API-Key match found in the list is used, 84 | // i.e. 'OR' semantics. 85 | // 86 | // The following default policies are used to generate the 87 | // `request.api_key` attribute if no explicit APIKey is defined. 88 | // 89 | // `query: key, `query: api_key`, and then `header: x-api-key` 90 | // 91 | repeated APIKey api_keys = 3; 92 | } 93 | 94 | // HTTPAPISpecPattern defines a single pattern to match against 95 | // incoming HTTP requests. The per-pattern list of attributes is 96 | // generated if both the http_method and uri_template match. In 97 | // addition, the top-level list of attributes in the HTTPAPISpec is also 98 | // generated. 99 | // 100 | // pattern: 101 | // - attributes 102 | // api.operation: doFooBar 103 | // httpMethod: GET 104 | // uriTemplate: /foo/bar 105 | // 106 | message HTTPAPISpecPattern { 107 | // List of attributes that are generated if the HTTP request matches 108 | // the specified http_method and uri_template. This typically 109 | // includes the "api.operation" attribute. 110 | Attributes attributes = 1; 111 | 112 | // HTTP request method to match against as defined by 113 | // [rfc7231](https://tools.ietf.org/html/rfc7231#page-21). For 114 | // example: GET, HEAD, POST, PUT, DELETE. 115 | string http_method = 2; 116 | 117 | oneof pattern { 118 | // URI template to match against as defined by 119 | // [rfc6570](https://tools.ietf.org/html/rfc6570). For example, the 120 | // following are valid URI templates: 121 | // 122 | // /pets 123 | // /pets/{id} 124 | // /dictionary/{term:1}/{term} 125 | // /search{?q*,lang} 126 | // 127 | string uri_template = 3; 128 | 129 | // EXPERIMENTAL: 130 | // 131 | // ecmascript style regex-based match as defined by 132 | // [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). For 133 | // example, 134 | // 135 | // "^/pets/(.*?)?" 136 | // 137 | string regex = 4; 138 | } 139 | } 140 | 141 | // APIKey defines the explicit configuration for generating the 142 | // `request.api_key` attribute from HTTP requests. 143 | // 144 | // See https://swagger.io/docs/specification/authentication/api-keys 145 | // for a general overview of API keys as defined by OpenAPI. 146 | message APIKey { 147 | oneof key { 148 | // API Key is sent as a query parameter. `query` represents the 149 | // query string parameter name. 150 | // 151 | // For example, `query=api_key` should be used with the 152 | // following request: 153 | // 154 | // GET /something?api_key=abcdef12345 155 | // 156 | string query = 1; 157 | 158 | // API key is sent in a request header. `header` represents the 159 | // header name. 160 | // 161 | // For example, `header=X-API-KEY` should be used with the 162 | // following request: 163 | // 164 | // GET /something HTTP/1.1 165 | // X-API-Key: abcdef12345 166 | // 167 | string header = 2; 168 | 169 | // API key is sent in a 170 | // [cookie](https://swagger.io/docs/specification/authentication/cookie-authentication), 171 | // 172 | // For example, `cookie=X-API-KEY` should be used for the 173 | // following request: 174 | // 175 | // GET /something HTTP/1.1 176 | // Cookie: X-API-KEY=abcdef12345 177 | // 178 | string cookie = 3; 179 | } 180 | } 181 | 182 | // HTTPAPISpecReference defines a reference to an HTTPAPISpec. This is 183 | // typically used for establishing bindings between an HTTPAPISpec and an 184 | // IstioService. For example, the following defines an 185 | // HTTPAPISpecReference for service `foo` in namespace `bar`. 186 | // 187 | // - name: foo 188 | // namespace: bar 189 | // 190 | message HTTPAPISpecReference { 191 | // REQUIRED. The short name of the HTTPAPISpec. This is the resource 192 | // name defined by the metadata name field. 193 | string name = 1; 194 | 195 | // Optional namespace of the HTTPAPISpec. Defaults to the encompassing 196 | // HTTPAPISpecBinding's metadata namespace field. 197 | string namespace = 2; 198 | } 199 | 200 | // HTTPAPISpecBinding defines the binding between HTTPAPISpecs and one or more 201 | // IstioService. For example, the following establishes a binding 202 | // between the HTTPAPISpec `petstore` and service `foo` in namespace `bar`. 203 | // 204 | // apiVersion: config.istio.io/v1alpha2 205 | // kind: HTTPAPISpecBinding 206 | // metadata: 207 | // name: my-binding 208 | // namespace: default 209 | // spec: 210 | // services: 211 | // - name: foo 212 | // namespace: bar 213 | // api_specs: 214 | // - name: petstore 215 | // namespace: default 216 | // 217 | message HTTPAPISpecBinding { 218 | // REQUIRED. One or more services to map the listed HTTPAPISpec onto. 219 | repeated IstioService services = 1; 220 | 221 | // REQUIRED. One or more HTTPAPISpec references that should be mapped to 222 | // the specified service(s). The aggregate collection of match 223 | // conditions defined in the HTTPAPISpecs should not overlap. 224 | repeated HTTPAPISpecReference api_specs = 2; 225 | } 226 | -------------------------------------------------------------------------------- /protobuf/mixer/v1/config/client/auth.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Istio Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // This policy API is no longer supported, and soon be replaced by 16 | // [authentication 17 | // policy](https://github.com/istio/api/tree/master/authentication/v1alpha2) in 18 | // the near future. 19 | // Tracking issue: https://github.com/istio/istio/issues/4337 20 | // Pre-release note: https://goo.gl/43usPn 21 | 22 | syntax = "proto3"; 23 | 24 | package istio.mixer.v1.config.client; 25 | 26 | option go_package = "istio.io/api/mixer/v1/config/client"; 27 | 28 | import "gogoproto/gogo.proto"; 29 | import "google/protobuf/duration.proto"; 30 | import "mixer/v1/config/client/service.proto"; 31 | 32 | option (gogoproto.goproto_getters_all) = false; 33 | option (gogoproto.equal_all) = false; 34 | option (gogoproto.gostring_all) = false; 35 | 36 | // JSON Web Token (JWT) token format for authentication as defined by 37 | // https://tools.ietf.org/html/rfc7519. See [OAuth 38 | // 2.0](https://tools.ietf.org/html/rfc6749) and [OIDC 39 | // 1.0](http://openid.net/connect) for how this is used in the whole 40 | // authentication flow. 41 | // 42 | // Example, 43 | // 44 | // issuer: https://example.com 45 | // audiences: 46 | // - bookstore_android.apps.googleusercontent.com 47 | // bookstore_web.apps.googleusercontent.com 48 | // jwks_uri: https://example.com/.well-known/jwks.json 49 | // 50 | message JWT { 51 | // Identifies the principal that issued the JWT. See 52 | // https://tools.ietf.org/html/rfc7519#section-4.1.1 53 | // Usually a URL or an email address. 54 | // 55 | // Example: https://securetoken.google.com 56 | // Example: 1234567-compute@developer.gserviceaccount.com 57 | // 58 | string issuer = 1; 59 | 60 | // The list of JWT 61 | // [audiences](https://tools.ietf.org/html/rfc7519#section-4.1.3). 62 | // that are allowed to access. A JWT containing any of these 63 | // audiences will be accepted. 64 | // 65 | // The service name will be accepted if audiences is empty. 66 | // 67 | // Example: 68 | // 69 | // audiences: 70 | // - bookstore_android.apps.googleusercontent.com 71 | // bookstore_web.apps.googleusercontent.com 72 | // 73 | repeated string audiences = 2; 74 | 75 | // URL of the provider's public key set to validate signature of the 76 | // JWT. See [OpenID 77 | // Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata). 78 | // 79 | // Optional if the key set document can either (a) be retrieved from 80 | // [OpenID 81 | // Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html) of 82 | // the issuer or (b) inferred from the email domain of the issuer (e.g. a 83 | // Google service account). 84 | // 85 | // Example: https://www.googleapis.com/oauth2/v1/certs 86 | string jwks_uri = 3; 87 | 88 | // If true, forward the entire base64 encoded JWT in the HTTP request. 89 | // If false, remove the JWT from the HTTP request and do not forward to the 90 | // application. 91 | bool forward_jwt = 4; 92 | 93 | // Duration after which the cached public key should be expired. The 94 | // system wide default is applied if no duration is explicitly 95 | // specified. 96 | google.protobuf.Duration public_key_cache_duration = 5; 97 | 98 | // Defines where to extract the JWT from an HTTP request. 99 | // 100 | // If no explicit location is specified the following default 101 | // locations are tried in order: 102 | // 103 | // 1) The Authorization header using the Bearer schema, 104 | // e.g. Authorization: Bearer . (see 105 | // https://tools.ietf.org/html/rfc6750#section-2.1) 106 | // 107 | // 2) `access_token` query parameter (see 108 | // https://tools.ietf.org/html/rfc6750#section-2.3) 109 | // 110 | message Location { 111 | oneof scheme { 112 | // JWT is sent in a request header. `header` represents the 113 | // header name. 114 | // 115 | // For example, if `header=x-goog-iap-jwt-assertion`, the header 116 | // format will be x-goog-iap-jwt-assertion: . 117 | // 118 | string header = 1; 119 | 120 | // JWT is sent in a query parameter. `query` represents the 121 | // query parameter name. 122 | // 123 | // For example, `query=jwt_token`. 124 | string query = 2; 125 | } 126 | } 127 | // Zero or more locations to search for JWT in an HTTP request. 128 | repeated Location locations = 6; 129 | 130 | // This field is specific for Envoy proxy implementation. 131 | // It is the cluster name in the Envoy config for the jwks_uri. 132 | string jwks_uri_envoy_cluster = 7; 133 | } 134 | 135 | // Determines how to apply auth policies for individual requests. 136 | message EndUserAuthenticationPolicySpec { 137 | // List of JWT rules to valide. 138 | // 139 | // If the request includes a JWT it must match one of the JWT listed 140 | // here matched by the issuer. If validation is successfull the 141 | // follow attributes are included in requests to the mixer: 142 | // 143 | // request.auth.principal - The string of the issuer (`iss`) and 144 | // subject (`sub`) claims within a JWT concatenated with “/” 145 | // with a percent-encoded subject value 146 | // 147 | // request.auth.audiences - This should reflect the audience 148 | // (`aud`) claim within matched JWT. 149 | // 150 | // request.auth.presenter - The authorized presenter of the 151 | // credential. This value should reflect the optional Authorized 152 | // Presenter (`azp`) claim within a JWT 153 | // 154 | // If no match is found the request is rejected with HTTP status 155 | // code 401. 156 | // 157 | // JWT validation is skipped if the user's traffic request does not 158 | // include a JWT. 159 | repeated JWT jwts = 2; 160 | } 161 | 162 | // EndUserAuthenticationPolicySpecReference identifies a 163 | // EndUserAuthenticationPolicySpec that is bound to a set of services. 164 | message EndUserAuthenticationPolicySpecReference { 165 | // REQUIRED. The short name of the 166 | // EndUserAuthenticationPolicySpec. This is the resource name 167 | // defined by the metadata name field. 168 | string name = 1; 169 | 170 | // Optional namespace of the 171 | // EndUserAuthenticationPolicySpec. Defaults to the value of the 172 | // metadata namespace field. 173 | string namespace = 2; 174 | } 175 | 176 | // EndUserAuthenticationPolicySpecBinding defines the binding between 177 | // EndUserAuthenticationPolicySpecs and one or more IstioService. 178 | message EndUserAuthenticationPolicySpecBinding { 179 | // REQUIRED. One or more services to map the listed 180 | // EndUserAuthenticationPolicySpecs onto. 181 | repeated IstioService services = 1; 182 | 183 | // REQUIRED. One or more EndUserAuthenticationPolicySpecReference 184 | // that should be mapped to the specified service(s). 185 | repeated EndUserAuthenticationPolicySpecReference policies = 2; 186 | } 187 | -------------------------------------------------------------------------------- /protobuf/mixer/v1/config/client/client_config.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Istio Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | import "gogoproto/gogo.proto"; 18 | import "google/protobuf/duration.proto"; 19 | 20 | import "mixer/v1/attributes.proto"; 21 | import "mixer/v1/config/client/api_spec.proto"; 22 | import "mixer/v1/config/client/quota.proto"; 23 | import "mixer/v1/config/client/auth.proto"; 24 | 25 | // $title: Mixer Client 26 | // $overview: Configuration state for the Mixer client library 27 | // $location: https://istio.io/docs/reference/config/istio.mixer.v1.config.client.html 28 | 29 | package istio.mixer.v1.config.client; 30 | 31 | option go_package="istio.io/api/mixer/v1/config/client"; 32 | 33 | option (gogoproto.goproto_getters_all) = false; 34 | option (gogoproto.equal_all) = false; 35 | option (gogoproto.gostring_all) = false; 36 | 37 | // Specifies the behavior when the client is unable to connect to Mixer. 38 | message NetworkFailPolicy { 39 | // Describes the policy. 40 | enum FailPolicy { 41 | // If network connection fails, request is allowed and delivered to the service. 42 | FAIL_OPEN = 0; 43 | 44 | // If network connection fails, request is rejected. 45 | FAIL_CLOSE = 1; 46 | } 47 | 48 | // Specifies the behavior when the client is unable to connect to Mixer. 49 | FailPolicy policy = 1; 50 | } 51 | 52 | // Defines the per-service client configuration. 53 | message ServiceConfig { 54 | // If true, do not call Mixer Check. 55 | bool disable_check_calls = 1; 56 | 57 | // If true, do not call Mixer Report. 58 | bool disable_report_calls = 2; 59 | 60 | // Send these attributes to Mixer in both Check and Report. This 61 | // typically includes the "destination.service" attribute. 62 | Attributes mixer_attributes = 3; 63 | 64 | // HTTP API specifications to generate API attributes. 65 | repeated HTTPAPISpec http_api_spec = 4; 66 | 67 | // Quota specifications to generate quota requirements. 68 | repeated QuotaSpec quota_spec = 5; 69 | 70 | // End user authentication policy. 71 | EndUserAuthenticationPolicySpec end_user_authn_spec = 6; 72 | 73 | // Specifies the behavior when the client is unable to connect to Mixer. 74 | // This is the service-level policy. It overrides 75 | // [mesh-level policy][istio.mixer.v1.config.client.TransportConfig.network_fail_policy]. 76 | NetworkFailPolicy network_fail_policy = 7; 77 | } 78 | 79 | // Defines the transport config on how to call Mixer. 80 | message TransportConfig { 81 | // The flag to disable check cache. 82 | bool disable_check_cache = 1; 83 | 84 | // The flag to disable quota cache. 85 | bool disable_quota_cache = 2; 86 | 87 | // The flag to disable report batch. 88 | bool disable_report_batch = 3; 89 | 90 | // Specifies the behavior when the client is unable to connect to Mixer. 91 | // This is the mesh level policy. The default value for policy is FAIL_OPEN. 92 | NetworkFailPolicy network_fail_policy = 4; 93 | 94 | // Specify refresh interval to write mixer client statistics to Envoy share 95 | // memory. If not specified, the interval is 10 seconds. 96 | google.protobuf.Duration stats_update_interval = 5; 97 | 98 | // Name of the cluster that will forward check calls to a pool of mixer 99 | // servers. Defaults to "mixer_server". By using different names for 100 | // checkCluster and reportCluster, it is possible to have one set of 101 | // mixer servers handle check calls, while another set of mixer servers 102 | // handle report calls. 103 | // 104 | // NOTE: Any value other than the default "mixer_server" will require the 105 | // Istio Grafana dashboards to be reconfigured to use the new name. 106 | string check_cluster = 6; 107 | 108 | // Name of the cluster that will forward report calls to a pool of mixer 109 | // servers. Defaults to "mixer_server". By using different names for 110 | // checkCluster and reportCluster, it is possible to have one set of 111 | // mixer servers handle check calls, while another set of mixer servers 112 | // handle report calls. 113 | // 114 | // NOTE: Any value other than the default "mixer_server" will require the 115 | // Istio Grafana dashboards to be reconfigured to use the new name. 116 | string report_cluster = 7; 117 | } 118 | 119 | // Defines the client config for HTTP. 120 | message HttpClientConfig { 121 | // The transport config. 122 | TransportConfig transport = 1; 123 | 124 | // Map of control configuration indexed by destination.service. This 125 | // is used to support per-service configuration for cases where a 126 | // mixerclient serves multiple services. 127 | map service_configs = 2; 128 | 129 | // Default destination service name if none was specified in the 130 | // client request. 131 | string default_destination_service = 3; 132 | 133 | // Default attributes to send to Mixer in both Check and 134 | // Report. This typically includes "destination.ip" and 135 | // "destination.uid" attributes. 136 | Attributes mixer_attributes = 4; 137 | 138 | // Default attributes to forward to upstream. This typically 139 | // includes the "source.ip" and "source.uid" attributes. 140 | Attributes forward_attributes = 5; 141 | } 142 | 143 | // Defines the client config for TCP. 144 | message TcpClientConfig { 145 | // The transport config. 146 | TransportConfig transport = 1; 147 | 148 | // Default attributes to send to Mixer in both Check and 149 | // Report. This typically includes "destination.ip" and 150 | // "destination.uid" attributes. 151 | Attributes mixer_attributes = 2; 152 | 153 | // If set to true, disables mixer check calls. 154 | bool disable_check_calls = 3; 155 | 156 | // If set to true, disables mixer check calls. 157 | bool disable_report_calls = 4; 158 | 159 | // Quota specifications to generate quota requirements. 160 | // It applies on the new TCP connections. 161 | QuotaSpec connection_quota_spec = 5; 162 | 163 | // Specify report interval to send periodical reports for long TCP 164 | // connections. If not specified, the interval is 10 seconds. This interval 165 | // should not be less than 1 second, otherwise it will be reset to 1 second. 166 | google.protobuf.Duration report_interval = 6; 167 | } 168 | -------------------------------------------------------------------------------- /protobuf/mixer/v1/config/client/quota.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Istio Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package istio.mixer.v1.config.client; 18 | 19 | option go_package="istio.io/api/mixer/v1/config/client"; 20 | 21 | import "gogoproto/gogo.proto"; 22 | import "mixer/v1/config/client/service.proto"; 23 | 24 | option (gogoproto.goproto_getters_all) = false; 25 | option (gogoproto.equal_all) = false; 26 | option (gogoproto.gostring_all) = false; 27 | 28 | // Specifies runtime quota rules. 29 | // * Uses Istio attributes to match individual requests 30 | // * Specifies list of quotas to use for matched requests. 31 | // 32 | // Example1: 33 | // Charge "request_count" quota with 1 amount for all requests. 34 | // 35 | // QuotaSpec: 36 | // - rules 37 | // - quotas: 38 | // quota: request_count 39 | // charge: 1 40 | // 41 | // Example2: 42 | // For HTTP POST requests with path are prefixed with /books or 43 | // api.operation is create_books, charge two quotas: 44 | // * write_count of 1 amount 45 | // * request_count of 5 amount. 46 | // 47 | // QuotaSpec: 48 | // - rules: 49 | // - match: 50 | // clause: 51 | // request.path: 52 | // string_prefix: /books 53 | // request.http_method: 54 | // string_exact: POST 55 | // - match: 56 | // clause: 57 | // api.operation: 58 | // string_exact: create_books 59 | // - quotas: 60 | // quota: write_count 61 | // charge: 1 62 | // - quotas: 63 | // quota: request_count 64 | // charge: 5 65 | 66 | // Determines the quotas used for individual requests. 67 | message QuotaSpec { 68 | // A list of Quota rules. 69 | repeated QuotaRule rules = 1; 70 | } 71 | 72 | // Specifies a rule with list of matches and list of quotas. 73 | // If any clause matched, the list of quotas will be used. 74 | message QuotaRule { 75 | // If empty, match all request. 76 | // If any of match is true, it is matched. 77 | repeated AttributeMatch match = 1; 78 | 79 | // The list of quotas to charge. 80 | repeated Quota quotas = 2; 81 | } 82 | 83 | // Describes how to match a given string in HTTP headers. Match is 84 | // case-sensitive. 85 | message StringMatch { 86 | oneof match_type { 87 | // exact string match 88 | string exact = 1; 89 | // prefix-based match 90 | string prefix = 2; 91 | // ECMAscript style regex-based match 92 | string regex = 3; 93 | } 94 | } 95 | 96 | // Specifies a match clause to match Istio attributes 97 | message AttributeMatch { 98 | // Map of attribute names to StringMatch type. 99 | // Each map element specifies one condition to match. 100 | // 101 | // Example: 102 | // 103 | // clause: 104 | // source.uid: 105 | // exact: SOURCE_UID 106 | // request.http_method: 107 | // exact: POST 108 | map clause = 1; 109 | } 110 | 111 | // Specifies a quota to use with quota name and amount. 112 | message Quota { 113 | // The quota name to charge 114 | string quota = 1; 115 | 116 | // The quota amount to charge 117 | int64 charge = 2; 118 | } 119 | 120 | // QuotaSpecBinding defines the binding between QuotaSpecs and one or more 121 | // IstioService. 122 | message QuotaSpecBinding { 123 | // REQUIRED. One or more services to map the listed QuotaSpec onto. 124 | repeated IstioService services = 1; 125 | 126 | // QuotaSpecReference uniquely identifies the QuotaSpec used in the 127 | // Binding. 128 | message QuotaSpecReference { 129 | // REQUIRED. The short name of the QuotaSpec. This is the resource 130 | // name defined by the metadata name field. 131 | string name = 1; 132 | 133 | // Optional namespace of the QuotaSpec. Defaults to the value of the 134 | // metadata namespace field. 135 | string namespace = 2; 136 | } 137 | 138 | // REQUIRED. One or more QuotaSpec references that should be mapped to 139 | // the specified service(s). The aggregate collection of match 140 | // conditions defined in the QuotaSpecs should not overlap. 141 | repeated QuotaSpecReference quota_specs = 2; 142 | } 143 | -------------------------------------------------------------------------------- /protobuf/mixer/v1/config/client/service.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Istio Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package istio.mixer.v1.config.client; 18 | 19 | option go_package="istio.io/api/mixer/v1/config/client"; 20 | 21 | import "gogoproto/gogo.proto"; 22 | 23 | option (gogoproto.goproto_getters_all) = false; 24 | option (gogoproto.equal_all) = false; 25 | option (gogoproto.gostring_all) = false; 26 | 27 | // NOTE: this is a duplicate of proxy.v1.config.IstioService from 28 | // proxy/v1alpha1/config/route_rules.proto. 29 | // 30 | // Mixer protobufs have gogoproto specific options which are not 31 | // compatiable with the proxy's vanilla protobufs. Ideally, these 32 | // protobuf options be reconciled so fundamental istio concepts and 33 | // types can be shared by components. Until then, make a copy of 34 | // IstioService for mixerclient to use. 35 | 36 | // IstioService identifies a service and optionally service version. 37 | // The FQDN of the service is composed from the name, namespace, and implementation-specific domain suffix 38 | // (e.g. on Kubernetes, "reviews" + "default" + "svc.cluster.local" -> "reviews.default.svc.cluster.local"). 39 | message IstioService { 40 | // The short name of the service such as "foo". 41 | string name = 1; 42 | 43 | // Optional namespace of the service. Defaults to value of metadata namespace field. 44 | string namespace = 2; 45 | 46 | // Domain suffix used to construct the service FQDN in implementations that support such specification. 47 | string domain = 3; 48 | 49 | // The service FQDN. 50 | string service = 4; 51 | 52 | // Optional one or more labels that uniquely identify the service version. 53 | // 54 | // *Note:* When used for a RouteRule destination, labels MUST be empty. 55 | // 56 | map labels = 5; 57 | } 58 | -------------------------------------------------------------------------------- /protobuf/mixer/v1/global_dictionary.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Istio Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | ################################################################################ 16 | # 17 | # 18 | # This is the global dictionary used by mixer client and server 19 | # for sending mixer attributes. 20 | # 21 | # The main reason using yaml format is that it allows comments like this. 22 | # 23 | # Important update rules: 24 | # * never remove, only add words at the end of file. 25 | # * http headers should be lower case. 26 | # * not duplication, all words have to be unique. 27 | # 28 | # Tools: 29 | # 1) It can be converted to json by: 30 | # python -c 'import sys, yaml, json; json.dump(yaml.load(sys.stdin), \ 31 | # sys.stdout, indent=4)' < global_dictionary.yaml 32 | # 33 | # 2) Use this to detect uniqueness and print out duplication: 34 | # python -c 'import yaml, collections; print [item for item, count in \ 35 | # collections.Counter(yaml.load(open("global_dictionary.yaml"))).items() if count > 1]' 36 | # 37 | 38 | # Section 1: Standard Istio attribute vocabulary 39 | # https://istio.io/docs/reference/config/mixer/attribute-vocabulary.html 40 | 41 | - source.ip 42 | - source.port 43 | - source.name 44 | - source.uid 45 | - source.namespace 46 | - source.labels 47 | - source.user 48 | 49 | # target.* attributes have been renamed to destination.* 50 | # They cannot be removed from this append only dictionary. 51 | - target.ip 52 | - target.port 53 | - target.service 54 | - target.name 55 | - target.uid 56 | - target.namespace 57 | - target.labels 58 | - target.user 59 | - request.headers 60 | - request.id 61 | - request.path 62 | - request.host 63 | - request.method 64 | - request.reason 65 | - request.referer 66 | - request.scheme 67 | - request.size 68 | - request.time 69 | - request.useragent 70 | - response.headers 71 | - response.size 72 | - response.time 73 | - response.duration 74 | - response.code 75 | 76 | # Section 2: HTTP common headers extracted from 77 | # https://tools.ietf.org/html/rfc7541#appendix-A 78 | - :authority 79 | - :method 80 | - :path 81 | - :scheme 82 | - :status 83 | - access-control-allow-origin 84 | - access-control-allow-methods 85 | - access-control-allow-headers 86 | - access-control-max-age 87 | - access-control-request-method 88 | - access-control-request-headers 89 | - accept-charset 90 | - accept-encoding 91 | - accept-language 92 | - accept-ranges 93 | - accept 94 | - access-control-allow 95 | - age 96 | - allow 97 | - authorization 98 | - cache-control 99 | - content-disposition 100 | - content-encoding 101 | - content-language 102 | - content-length 103 | - content-location 104 | - content-range 105 | - content-type 106 | - cookie 107 | - date 108 | - etag 109 | - expect 110 | - expires 111 | - from 112 | - host 113 | - if-match 114 | - if-modified-since 115 | - if-none-match 116 | - if-range 117 | - if-unmodified-since 118 | - keep-alive 119 | - last-modified 120 | - link 121 | - location 122 | - max-forwards 123 | - proxy-authenticate 124 | - proxy-authorization 125 | - range 126 | - referer 127 | - refresh 128 | - retry-after 129 | - server 130 | - set-cookie 131 | - strict-transport-sec 132 | - transfer-encoding 133 | - user-agent 134 | - vary 135 | - via 136 | - www-authenticate 137 | 138 | # HTTP methods 139 | - GET 140 | - POST 141 | 142 | # Common strings 143 | - http 144 | - envoy 145 | - '200' 146 | - Keep-Alive 147 | - chunked 148 | - x-envoy-service-time 149 | - x-forwarded-for 150 | - x-forwarded-host 151 | - x-forwarded-proto 152 | - x-http-method-override 153 | - x-request-id 154 | - x-requested-with 155 | 156 | # Popular content-type 157 | - application/json 158 | - application/xml 159 | - gzip 160 | - text/html 161 | - text/html; charset=utf-8 162 | - text/plain 163 | - text/plain; charset=utf-8 164 | 165 | # common strings 166 | - '0' 167 | - '1' 168 | - true 169 | - false 170 | - gzip, deflate 171 | - max-age=0 172 | - x-envoy-upstream-service-time 173 | - x-envoy-internal 174 | - x-envoy-expected-rq-timeout-ms 175 | - x-ot-span-context 176 | - x-b3-traceid 177 | - x-b3-sampled 178 | - x-b3-spanid 179 | - tcp 180 | 181 | # connection attributes 182 | - connection.id 183 | - connection.received.bytes 184 | - connection.received.bytes_total 185 | - connection.sent.bytes 186 | - connection.sent.bytes_total 187 | - connection.duration 188 | 189 | # context attributes 190 | - context.protocol 191 | - context.timestamp 192 | - context.time 193 | 194 | # common integer strings 195 | - 0 196 | - 1 197 | - 200 198 | - 302 199 | - 400 200 | - 401 201 | - 403 202 | - 404 203 | - 409 204 | - 429 205 | - 499 206 | - 500 207 | - 501 208 | - 502 209 | - 503 210 | - 504 211 | 212 | - destination.ip 213 | - destination.port 214 | - destination.service 215 | - destination.name 216 | - destination.uid 217 | - destination.namespace 218 | - destination.labels 219 | - destination.user 220 | 221 | - source.service 222 | 223 | # api attributes 224 | - api.service 225 | - api.version 226 | - api.operation 227 | - api.protocol 228 | 229 | # auth attributes 230 | - request.auth.principal 231 | - request.auth.audiences 232 | - request.auth.presenter 233 | 234 | # api key 235 | - request.api_key 236 | 237 | # check.error_code and error_message 238 | - check.error_code 239 | - check.error_message 240 | -------------------------------------------------------------------------------- /protobuf/mixer/v1/report.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Istio Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package istio.mixer.v1; 18 | 19 | option go_package = "istio.io/api/mixer/v1"; 20 | 21 | import "gogoproto/gogo.proto"; 22 | import "mixer/v1/attributes.proto"; 23 | 24 | option (gogoproto.goproto_getters_all) = false; 25 | option (gogoproto.equal_all) = false; 26 | option (gogoproto.gostring_all) = false; 27 | 28 | // Used to report telemetry after performing one or more actions. 29 | message ReportRequest { 30 | // The attributes to use for this request. 31 | // 32 | // Each `Attributes` element represents the state of a single action. Multiple actions 33 | // can be provided in a single message in order to improve communication efficiency. The 34 | // client can accumulate a set of actions and send them all in one single message. 35 | // 36 | // Although each `Attributes` message is semantically treated as an independent 37 | // stand-alone entity unrelated to the other attributes within the message, this 38 | // message format leverages delta-encoding between attribute messages in order to 39 | // substantially reduce the request size and improve end-to-end efficiency. Each 40 | // individual set of attributes is used to modify the previous set. This eliminates 41 | // the need to redundantly send the same attributes multiple times over within 42 | // a single request. 43 | // 44 | // If a client is not sophisticated and doesn't want to use delta-encoding, 45 | // a degenerate case is to include all attributes in every individual message. 46 | repeated CompressedAttributes attributes = 1 [(gogoproto.nullable) = false]; 47 | 48 | // The default message-level dictionary for all the attributes. 49 | // Individual attribute messages can have their own dictionaries, but if they don't 50 | // then this set of words, if it is provided, is used instead. 51 | // 52 | // This makes it possible to share the same dictionary for all attributes in this 53 | // request, which can substantially reduce the overall request size. 54 | repeated string default_words = 2; 55 | 56 | // The number of words in the global dictionary. 57 | // To detect global dictionary out of sync between client and server. 58 | uint32 global_word_count = 3; 59 | } 60 | 61 | // Used to carry responses to telemetry reports 62 | message ReportResponse { 63 | } 64 | -------------------------------------------------------------------------------- /protobuf/mixer/v1/service.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Istio Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | // $title: Mixer 18 | // $overview: API definitions to interact with Mixer 19 | // $location: https://istio.io/docs/reference/api/istio.mixer.v1.html 20 | // $front_matter: redirect_from: /docs/reference/api/mixer/mixer.html 21 | 22 | 23 | // This package defines the Mixer API that the sidecar proxy uses to perform 24 | // precondition checks, manage quotas, and report telemetry. 25 | package istio.mixer.v1; 26 | 27 | option go_package = "istio.io/api/mixer/v1"; 28 | option cc_generic_services = true; 29 | 30 | import "mixer/v1/check.proto"; 31 | import "mixer/v1/report.proto"; 32 | 33 | // Mixer provides three core features: 34 | // 35 | // - *Precondition Checking*. Enables callers to verify a number of preconditions 36 | // before responding to an incoming request from a service consumer. 37 | // Preconditions can include whether the service consumer is properly 38 | // authenticated, is on the service’s whitelist, passes ACL checks, and more. 39 | // 40 | // - *Quota Management*. Enables services to allocate and free quota on a number 41 | // of dimensions, Quotas are used as a relatively simple resource management tool 42 | // to provide some fairness between service consumers when contending for limited 43 | // resources. Rate limits are examples of quotas. 44 | // 45 | // - *Telemetry Reporting*. Enables services to report logging and monitoring. 46 | // In the future, it will also enable tracing and billing streams intended for 47 | // both the service operator as well as for service consumers. 48 | service Mixer { 49 | // Checks preconditions and allocate quota before performing an operation. 50 | // The preconditions enforced depend on the set of supplied attributes and 51 | // the active configuration. 52 | rpc Check(CheckRequest) returns (CheckResponse) {} 53 | 54 | // Reports telemetry, such as logs and metrics. 55 | // The reported information depends on the set of supplied attributes and the 56 | // active configuration. 57 | rpc Report(ReportRequest) returns (ReportResponse) {} 58 | } 59 | -------------------------------------------------------------------------------- /protobuf/proxy/v1/config/dest_policy.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Istio Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | syntax = "proto3"; 15 | 16 | import "google/protobuf/any.proto"; 17 | import "google/protobuf/duration.proto"; 18 | 19 | package istio.proxy.v1.config; 20 | 21 | // DestinationPolicy defines client/caller-side policies that determine how 22 | // to handle traffic bound to a particular destination service. The policy 23 | // specifies configuration for load balancing and circuit breakers. For 24 | // example, a simple load balancing policy for the reviews service would 25 | // look as follows: 26 | // 27 | // destination: reviews.default.svc.cluster.local 28 | // policy: 29 | // - loadBalancing: RANDOM 30 | // simpleCb: 31 | // maxConnections: 1000 32 | // 33 | // Policies are applicable per individual service versions. ONLY 34 | // ONE policy can be defined per service version. Policy CANNOT be empty. 35 | message DestinationPolicy { 36 | // REQUIRED. Service name for which the service version is defined. The 37 | // value MUST BE a fully-qualified domain name, 38 | // e.g. _my-service.default.svc.cluster.local_. 39 | string destination = 1; 40 | 41 | // REQUIRED. List of policies, one per service version. 42 | repeated DestinationVersionPolicy policy = 2; 43 | } 44 | 45 | // A destination policy can be restricted to a particular version of a 46 | // service or applied to all versions. The tags field in the 47 | // DestinationVersionPolicy allow restricting the scope of a 48 | // DestinationPolicy. For example, the following load balancing policy 49 | // applies to version v1 of the reviews service running in the prod 50 | // environment: 51 | // 52 | // destination: reviews.default.svc.cluster.local 53 | // policy: 54 | // - tags: 55 | // env: prod 56 | // version: v1 57 | // loadBalancing: RANDOM 58 | // 59 | // If tags are omitted, the policy applies for all versions of the 60 | // service. Policy CANNOT BE empty. 61 | // *Note:* Destination policies will be applied only if the corresponding 62 | // tagged instances are explicity routed to. In other words, for every 63 | // destination policy defined, atleast one route rule must refer to the 64 | // service version indicated in the destination policy. 65 | message DestinationVersionPolicy { 66 | // Optional set of tags that identify a particular version of the 67 | // destination service. If omitted, the policy will apply to all versions 68 | // of the service. (-- N.B. The map is used instead of 69 | // pstruct due to lack of serialization support in golang protobuf 70 | // library (see https://github.com/golang/protobuf/pull/208) --) 71 | map tags = 1; 72 | 73 | // Load balancing policy. 74 | LoadBalancing load_balancing = 2; 75 | 76 | // Circuit breaker policy. 77 | CircuitBreaker circuit_breaker = 3; 78 | 79 | //(-- Other custom policy implementations --) 80 | google.protobuf.Any custom = 100 ; 81 | } 82 | 83 | // Load balancing policy to use when forwarding traffic. These policies 84 | // directly correlate to [load balancer 85 | // types](https://lyft.github.io/envoy/docs/intro/arch_overview/load_balancing.html) 86 | // supported by Envoy. Example, 87 | // 88 | // destination: reviews.default.svc.cluster.local 89 | // policy: 90 | // - loadBalancing: RANDOM 91 | // 92 | message LoadBalancing { 93 | // Load balancing algorithms supported by Envoy proxy. 94 | enum SimpleLBPolicy { 95 | 96 | // Simple round robin policy. 97 | ROUND_ROBIN = 0; 98 | 99 | // The least request load balancer uses an O(1) algorithm which selects 100 | // two random healthy hosts and picks the host which has fewer active 101 | // requests. 102 | LEAST_CONN = 1; 103 | 104 | // The random load balancer selects a random healthy host. The random 105 | // load balancer generally performs better than round robin if no health 106 | // checking policy is configured. 107 | RANDOM = 2; 108 | } 109 | oneof lb_policy { 110 | // Load balancing policy name (as defined in SimpleLBPolicy below) 111 | SimpleLBPolicy name = 1; 112 | //(-- Custom LB policy implementations --) 113 | google.protobuf.Any custom = 2 ; 114 | } 115 | } 116 | 117 | // Circuit breaker configuration for Envoy. The circuit breaker 118 | // implementation is fine-grained in that it tracks the success/failure 119 | // rates of individual hosts in the load balancing pool. Hosts that 120 | // continually return errors for API calls are ejected from the pool for a 121 | // pre-defined period of time. See Envoy's [outlier 122 | // detection](https://lyft.github.io/envoy/docs/intro/arch_overview/outlier.html) 123 | // for more details. 124 | message CircuitBreaker { 125 | // Parameters to tune Envoy's circuit breaker configuration. A simple 126 | // circuit breaker can be set based on a number of criteria such as 127 | // connection and request limits. For example, the following destination 128 | // policy sets a limit of 100 connections to "reviews" service version 129 | // "v1" backends. 130 | // 131 | // destination: reviews.default.svc.cluster.local 132 | // policy: 133 | // - tags: 134 | // version: v1 135 | // circuitBreaker: 136 | // simpleCb: 137 | // maxConnections: 100 138 | // 139 | // The following destination policy sets a limit of 100 connections and 140 | // 1000 concurrent requests, with no more than 10 req/connection to 141 | // "reviews" service version "v1" backends. In addition, it configures 142 | // hosts to be scanned every 5 mins, such that any host that fails 7 143 | // consecutive times with 5XX error code will be ejected for 15 minutes. 144 | // 145 | // destination: reviews.default.svc.cluster.local 146 | // policy: 147 | // - tags: 148 | // version: v1 149 | // circuitBreaker: 150 | // simpleCb: 151 | // maxConnections: 100 152 | // httpMaxRequests: 1000 153 | // httpMaxRequestsPerConnection: 10 154 | // httpConsecutiveErrors: 7 155 | // sleepWindow: 15m 156 | // httpDetectionInterval: 5m 157 | // 158 | message SimpleCircuitBreakerPolicy { 159 | // Maximum number of connections to a backend. 160 | int32 max_connections = 1; 161 | 162 | // Maximum number of pending requests to a backend. Default 1024 163 | int32 http_max_pending_requests = 2; 164 | 165 | // Maximum number of requests to a backend. Default 1024 166 | int32 http_max_requests = 3; 167 | 168 | // Minimum time the circuit will be closed. format: 1h/1m/1s/1ms. MUST 169 | // BE >=1ms. Default is 30s. 170 | google.protobuf.Duration sleep_window = 4; 171 | 172 | // Number of 5XX errors before circuit is opened. Defaults to 5. 173 | int32 http_consecutive_errors = 5; 174 | 175 | // Time interval between ejection sweep analysis. format: 176 | // 1h/1m/1s/1ms. MUST BE >=1ms. Default is 10s. 177 | google.protobuf.Duration http_detection_interval = 6; 178 | 179 | // Maximum number of requests per connection to a backend. Setting this 180 | // parameter to 1 disables keep alive. 181 | int32 http_max_requests_per_connection = 7; 182 | 183 | // Maximum % of hosts in the load balancing pool for the destination 184 | // service that can be ejected by the circuit breaker. Defaults to 185 | // 10%. 186 | int32 http_max_ejection_percent = 8; 187 | } 188 | oneof cb_policy { 189 | SimpleCircuitBreakerPolicy simple_cb = 1; 190 | //(-- For proxies that support custom circuit breaker policies. --) 191 | google.protobuf.Any custom = 2 ; 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /protobuf/proxy/v1/config/http_fault.proto: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2017 Istio Authors 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | syntax = "proto3"; 18 | 19 | import "google/protobuf/duration.proto"; 20 | 21 | package istio.proxy.v1.config; 22 | 23 | // HTTPFaultInjection can be used to specify one or more faults to inject 24 | // while forwarding http requests to the destination specified in the route 25 | // rule. Fault specification is part of a route rule. Faults include 26 | // aborting the Http request from downstream service, and/or delaying 27 | // proxying of requests. A fault rule MUST HAVE delay or abort or both. 28 | // 29 | // *Note:* Delay and abort faults are independent of one another, even if 30 | // both are specified simultaneously. 31 | message HTTPFaultInjection { 32 | // Delay requests before forwarding, emulating various failures such as 33 | // network issues, overloaded upstream service, etc. 34 | Delay delay = 1; 35 | 36 | // Abort Http request attempts and return error codes back to downstream 37 | // service, giving the impression that the upstream service is faulty. 38 | Abort abort = 2; 39 | 40 | // Delay specification is used to inject latency into the request 41 | // forwarding path. The following example will introduce a 5 second delay 42 | // in 10% of the requests to the "v1" version of the "reviews" 43 | // service. 44 | // 45 | // destination: reviews.default.svc.cluster.local 46 | // route: 47 | // - tags: 48 | // version: v1 49 | // httpFault: 50 | // delay: 51 | // percent: 10 52 | // fixedDelay: 5s 53 | // 54 | // The _fixedDelay_ field is used to indicate the amount of delay in 55 | // seconds. An optional _percent_ field, a value between 0 and 100, can 56 | // be used to only delay a certain percentage of requests. If left 57 | // unspecified, all request will be delayed. 58 | message Delay { 59 | // percentage of requests on which the delay will be injected (0-100) 60 | float percent = 1; 61 | oneof http_delay_type { 62 | // REQUIRED. Add a fixed delay before forwarding the request. Format: 1h/1m/1s/1ms. MUST be >=1ms. 63 | google.protobuf.Duration fixed_delay = 2; 64 | // (-- Add a delay (based on an exponential function) before forwarding 65 | // the request. mean delay needed to derive the exponential delay 66 | // values --) 67 | google.protobuf.Duration exponential_delay = 3 ; 68 | } 69 | // (-- Specify delay duration as part of Http request. 70 | // TODO: The semantics and syntax of the headers is undefined. --) 71 | string override_header_name = 4 ; 72 | } 73 | 74 | // Abort specification is used to prematurely abort a request with a 75 | // pre-specified error code. The following example will return an HTTP 76 | // 400 error code for 10% of the requests to the "ratings" service "v1". 77 | // 78 | // destination: ratings.default.svc.cluster.local 79 | // route: 80 | // - tags: 81 | // version: v1 82 | // httpFault: 83 | // abort: 84 | // percent: 10 85 | // httpStatus: 400 86 | // 87 | // The _httpStatus_ field is used to indicate the HTTP status code to 88 | // return to the caller. The optional _percent_ field, a value between 0 89 | // and 100, is used to only abort a certain percentage of requests. If 90 | // not specified, all requests are aborted. 91 | message Abort { 92 | // percentage of requests to be aborted with the error code provided (0-100). 93 | float percent = 1; 94 | oneof error_type { 95 | string grpc_status = 2 ; 96 | string http2_error = 3 ; 97 | // REQUIRED. HTTP status code to use to abort the Http request. 98 | int32 http_status = 4; 99 | } 100 | // (-- Specify abort code as part of Http request. 101 | // TODO: The semantics and syntax of the headers is undefined. --) 102 | string override_header_name = 5 ; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /protobuf/proxy/v1/config/l4_fault.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Istio Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | import "google/protobuf/duration.proto"; 18 | 19 | package istio.proxy.v1.config; 20 | 21 | // (-- Faults can be injected into the connections from downstream by the 22 | // Envoy, for testing the failure recovery capabilities of downstream 23 | // services. Faults include aborting the connection from downstream 24 | // service, delaying proxying of connection to the destination 25 | // service, and throttling the bandwidth of the connection (either 26 | // end). Bandwidth throttling for failure testing should not be confused 27 | // with the rate limiting policy enforcement provided by the Mixer 28 | // component. L4 fault injection is not supported at the moment. --) 29 | message L4FaultInjection { 30 | // Unlike Http services, we have very little context for raw Tcp|Udp 31 | // connections. We could throttle bandwidth of the connections (slow down 32 | // the connection) and/or abruptly reset (terminate) the Tcp connection 33 | // after it has been established. 34 | // We first throttle (if set) and then terminate the connection. 35 | Throttle throttle = 1; 36 | Terminate terminate = 2; 37 | 38 | // Bandwidth throttling for Tcp and Udp connections 39 | message Throttle { 40 | // percentage of connections to throttle. 41 | float percent = 1; 42 | // bandwidth limit in "bits" per second between downstream and Envoy 43 | int64 downstream_limit_bps = 2; 44 | // bandwidth limits in "bits" per second between Envoy and upstream 45 | int64 upstream_limit_bps = 3; 46 | 47 | oneof throttle_after { 48 | // Wait a while after the connection is established, before 49 | // starting bandwidth throttling. This would allow us to inject fault 50 | // after the application protocol (e.g., MySQL) has had time to 51 | // establish sessions/whatever handshake necessary. 52 | google.protobuf.Duration throttle_after_period = 4; 53 | 54 | // Alternatively, we could wait for a certain number of bytes to be 55 | // transferred to upstream before throttling the bandwidth. 56 | double throttle_after_bytes = 5; 57 | } 58 | 59 | // Stop throttling after the given duration. If not set, the connection 60 | // will be throttled for its lifetime. 61 | google.protobuf.Duration throttle_for_period = 6; 62 | } 63 | 64 | // Abruptly reset (terminate) the Tcp connection after it has been 65 | // established, emulating remote server crash or link failure. 66 | message Terminate { 67 | // percentage of established Tcp connections to be terminated/reset 68 | float percent = 1; 69 | 70 | // Wait a while after the connection is established, before 71 | // terminating the connection. Set to 0 to terminate immediately on 72 | // connection establishment. 73 | 74 | // TODO: see if it makes sense to create a generic Duration type to 75 | // express time interval related configs. 76 | google.protobuf.Duration terminate_after_period = 2; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /protobuf/proxy/v1/config/proxy_mesh.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Istio Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | import "google/protobuf/duration.proto"; 18 | 19 | package istio.proxy.v1.config; 20 | 21 | // ProxyMeshConfig defines variables shared by all Envoy instances in the 22 | // Istio service mesh. 23 | message ProxyMeshConfig { 24 | // Address of the egress envoy service (e.g. _istio-egress:80_). 25 | string egress_proxy_address = 1; 26 | 27 | // Address of the discovery service exposing SDS, CDS, RDS (e.g. _istio-manager:8080_). 28 | string discovery_address = 2; 29 | 30 | // Address of the mixer service (e.g. _istio-mixer:9090_). 31 | string mixer_address = 3; 32 | 33 | // Address of the Zipkin service (e.g. _zipkin:9411_). 34 | string zipkin_address = 4; 35 | 36 | // Port on which egress envoy should listen for incoming connections from 37 | // other services. 38 | int32 proxy_listen_port = 5; 39 | 40 | // Port on which egress envoy should listen for administrative commands. 41 | int32 proxy_admin_port = 6; 42 | 43 | // The time in seconds that Envoy will drain connections during a hot 44 | // restart. MUST be >=1s (e.g., _1s/1m/1h_) 45 | google.protobuf.Duration drain_duration = 7; 46 | 47 | // The time in seconds that Envoy will wait before shutting down the 48 | // parent process during a hot restart. MUST be >=1s (e.g., _1s/1m/1h_). 49 | // MUST BE greater than _drain_duration_ parameter. 50 | google.protobuf.Duration parent_shutdown_duration = 8; 51 | 52 | // istio_service_cluster defines the name for the service_cluster that is 53 | // shared by all Envoy instances. This setting corresponds to 54 | // _--service-cluster_ flag in Envoy. In a typical Envoy deployment, the 55 | // _service-cluster_ flag is used to identify the caller, for 56 | // source-based routing scenarios. 57 | // 58 | // 59 | // Since Istio does not assign a local service/service version to each 60 | // Envoy instance, the name is same for all of them. However, the 61 | // source/caller's identity (e.g., IP address) is encoded in the 62 | // _--service-node_ flag when launching Envoy. When the RDS service 63 | // receives API calls from Envoy, it uses the value of the _service-node_ 64 | // flag to compute routes that are relative to the service instances 65 | // located at that IP address. 66 | string istio_service_cluster = 9; 67 | 68 | // Polling interval for service discovery. (MUST BE >=1ms) 69 | google.protobuf.Duration discovery_refresh_delay = 10; 70 | 71 | // Connection timeout used by Envoy. (MUST BE >=1ms) 72 | google.protobuf.Duration connect_timeout = 11; 73 | 74 | // Class of ingress resources to be processed by Istio ingress 75 | // controller. This corresponds to the value of 76 | // "kubernetes.io/ingress.class" annotation. 77 | string ingress_class = 20; 78 | 79 | // Name of the kubernetes service used for the istio ingress controller. 80 | string ingress_service = 21; 81 | 82 | enum IngressControllerMode { 83 | // Disables Istio ingress controller. 84 | OFF = 0; 85 | 86 | // Istio ingress controller will act on ingress resources that do not 87 | // contain any annotation or whose annotations match the value 88 | // specified in the ingress_class parameter described earlier. Use this 89 | // mode if Istio ingress controller will be the default ingress 90 | // controller for the entire kubernetes cluster. 91 | DEFAULT = 1; 92 | 93 | // Istio ingress controller will only act on ingress resources whose 94 | // annotations match the value specified in the ingress_class parameter 95 | // described earlier. Use this mode if Istio ingress controller will be 96 | // a secondary ingress controller (e.g., in addition to a 97 | // cloud-provided ingress controller). 98 | STRICT = 2; 99 | } 100 | 101 | // Defines whether to use Istio ingress controller for annotated or all ingress resources. 102 | IngressControllerMode ingress_controller_mode = 22; 103 | 104 | enum AuthPolicy { 105 | // Do not encrypt Envoy to Envoy traffic. 106 | NONE = 0; 107 | 108 | // Envoy to Envoy traffic is wrapped into mutual TLS connections. 109 | MUTUAL_TLS = 1; 110 | } 111 | 112 | // Authentication policy defines the global switch to control authentication 113 | // for Envoy-to-Envoy communication. 114 | AuthPolicy auth_policy = 100; 115 | 116 | // Path to the secrets used by the authentication policy. 117 | string auth_certs_path = 101; 118 | } 119 | -------------------------------------------------------------------------------- /snippets/tools.MD: -------------------------------------------------------------------------------- 1 | # Snippets 2 | 3 | 4 | ## Mixer 5 | 6 | port forward mixer server to localhost 7 | 8 | ```bash 9 | kubectl port-forward $(kubectl get pod -l istio=mixer -n istio-system -o jsonpath='{.items[0].metadata.name}') -n istio-system 9091:9091 10 | ``` 11 | 12 | watch logs 13 | ```bash 14 | kubectl logs -f $(kubectl get pod -l istio=mixer -n istio-system -o jsonpath='{.items[0].metadata.name}') -n istio-system -c mixer 15 | ``` -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | # Set up Mixer for testing 2 | 3 | ## Set up Istio for developer 4 | 5 | Follow instruction https://github.com/istio/istio/tree/master/devel 6 | 7 | Build mixer. This module works with 0.16 version, so be sure to use 0.16 tag. 8 | 9 | `cd $(ISTIO)/mixer 10 | git checkout 0.1.6 11 | bazel clean 12 | bazel build ... 13 | ` 14 | 15 | This should build mixc and mixs binary in the go path 16 | 17 | ## Set up book 18 | 19 | Set up BookInfo app as here: https://istio.io/docs/samples/bookinfo.html 20 | 21 | ## Set up local forward to remote k8 instance 22 | 23 | `kubectl get pods` 24 | 25 | `kubectl port-forward istio-mixer-2450814972-f2m3w 9091:9091` 26 | 27 | This will port forward local port 9091 to remote k8 mixer. 28 | 29 | ## Test mixer 30 | 31 | Test that mixer can be reached 32 | 33 | `./bazel-bin/cmd/client/mixc report -a target.service=reviews.default.svc.cluster.local --string_attributes request.headers=content-length:0` 34 | 35 | 36 | -------------------------------------------------------------------------------- /test/config/conf.d/http.conf: -------------------------------------------------------------------------------- 1 | 2 | 3 | upstream service1 { 4 | server localhost:9100; 5 | } 6 | 7 | 8 | 9 | #incoming 10 | server { 11 | 12 | listen 8000; 13 | 14 | mixer_source_ip 10.0.0.0; 15 | mixer_source_uid kubernetes://productpage-v1-2213572757-758cs.beta1; 16 | mixer_source_service productpage.beta1.svc.cluster.local; 17 | mixer_source_port 8000; 18 | mixer_destination_service abc.ns.svc.cluster.local; 19 | mixer_destination_uid details; 20 | 21 | 22 | location /report { 23 | mixer_report on; 24 | proxy_pass http://service1; 25 | } 26 | 27 | location /check { 28 | 29 | mixer_check on; 30 | proxy_pass http://service1; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /test/config/conf.d/remote.conf: -------------------------------------------------------------------------------- 1 | server { 2 | # listen 8.8.8.8:9500; 3 | 4 | location = /health { 5 | return 200; 6 | } 7 | 8 | } -------------------------------------------------------------------------------- /test/config/nginx.conf: -------------------------------------------------------------------------------- 1 | # test set up for mixer 2 | # this assume this is running inside the docker container runnin in the mac 3 | # mixer is running at local host port 9091. typically mixer running using port forward 4 | 5 | load_module modules/ngx_http_istio_mixer_module.so; 6 | 7 | 8 | worker_processes 1; 9 | 10 | error_log /var/log/nginx/error.log debug; 11 | 12 | events { 13 | worker_connections 10024; 14 | } 15 | 16 | 17 | http { 18 | include mime.types; 19 | 20 | 21 | mixer_server docker.for.mac.localhost; 22 | mixer_port 9091; 23 | 24 | include /etc/nginx/conf.d/*.conf; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /test/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cp test/config/nginx.conf /etc/nginx 3 | rm -rf /etc/nginx/conf.d/* 4 | cp test/config/conf.d/* /etc/nginx/conf.d 5 | node test/services/http.js 9100 > /var/log/u1.log 2> /var/log/u1.err & 6 | # tests/tproxy.sh & 7 | nginx -s reload -------------------------------------------------------------------------------- /test/iptable/prepare_proxy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Envoy initialization script responsible for setting up port forwarding. 3 | set -x 4 | set -o errexit 5 | set -o nounset 6 | set -o pipefail 7 | 8 | echo "running prepare_proxy" 9 | 10 | usage() { 11 | echo "${0} -p PORT -u UID [-h]" 12 | echo '' 13 | echo ' -p: Specify the envoy port to which redirect all TCP traffic' 14 | echo ' -u: Specify the UID of the user for which the redirection is not' 15 | echo ' applied. Typically, this is the UID of the proxy container' 16 | echo ' -i: Comma separated list of IP ranges in CIDR form to redirect to envoy (optional)' 17 | echo '' 18 | } 19 | 20 | IP_RANGES_INCLUDE="" 21 | 22 | while getopts ":p:u:e:i:h" opt; do 23 | case ${opt} in 24 | p) 25 | ENVOY_PORT=${OPTARG} 26 | ;; 27 | u) 28 | ENVOY_UID=${OPTARG} 29 | ;; 30 | i) 31 | IP_RANGES_INCLUDE=${OPTARG} 32 | ;; 33 | h) 34 | usage 35 | exit 0 36 | ;; 37 | \?) 38 | echo "Invalid option: -$OPTARG" >&2 39 | usage 40 | exit 1 41 | ;; 42 | esac 43 | done 44 | 45 | if [[ -z "${ENVOY_PORT-}" ]] || [[ -z "${ENVOY_UID-}" ]]; then 46 | echo "Please set both -p and -u parameters" 47 | usage 48 | exit 1 49 | fi 50 | 51 | # Create a new chain for redirecting inbound and outbound traffic to 52 | # the common Envoy port. 53 | iptables -t nat -N ISTIO_REDIRECT -m comment --comment "istio/redirect-common-chain" 54 | iptables -t nat -A ISTIO_REDIRECT -p tcp -j REDIRECT --to-port ${ENVOY_PORT} -m comment --comment "istio/redirect-to-envoy-port" 55 | 56 | # Redirect all inbound traffic to Envoy. 57 | iptables -t nat -A PREROUTING -j ISTIO_REDIRECT -m comment --comment "istio/install-istio-prerouting" 58 | 59 | # Create a new chain for selectively redirecting outbound packets to 60 | # Envoy. 61 | iptables -t nat -N ISTIO_OUTPUT -m comment --comment "istio/common-output-chain" 62 | 63 | # Jump to the ISTIO_OUTPUT chain from OUTPUT chain for all tcp 64 | # traffic. '-j RETURN' bypasses Envoy and '-j ISTIO_REDIRECT' 65 | # redirects to Envoy. 66 | iptables -t nat -A OUTPUT -p tcp -j ISTIO_OUTPUT -m comment --comment "istio/install-istio-output" 67 | 68 | # Redirect app calls to back itself via Envoy when using the service VIP or endpoint 69 | # address, e.g. appN => Envoy (client) => Envoy (server) => appN. 70 | iptables -t nat -A ISTIO_OUTPUT -o lo ! -d 127.0.0.1/32 -j ISTIO_REDIRECT -m comment --comment "istio/redirect-implicit-loopback" 71 | 72 | # Avoid infinite loops. Don't redirect Envoy traffic directly back to 73 | # Envoy for non-loopback traffic. 74 | iptables -t nat -A ISTIO_OUTPUT -m owner --uid-owner ${ENVOY_UID} -j RETURN -m comment --comment "istio/bypass-envoy" 75 | 76 | # Skip redirection for Envoy-aware applications and 77 | # container-to-container traffic both of which explicitly use 78 | # localhost. 79 | iptables -t nat -A ISTIO_OUTPUT -d 127.0.0.1/32 -j RETURN -m comment --comment "istio/bypass-explicit-loopback" 80 | 81 | # All outbound traffic will be redirected to Envoy by default. If 82 | # IP_RANGES_INCLUDE is non-empty, only traffic bound for the 83 | # destinations specified in this list will be captured. 84 | IFS=, 85 | if [ "${IP_RANGES_INCLUDE}" != "" ]; then 86 | for cidr in ${IP_RANGES_INCLUDE}; do 87 | iptables -t nat -A ISTIO_OUTPUT -d ${cidr} -j ISTIO_REDIRECT -m comment --comment "istio/redirect-ip-range-${cidr}" 88 | done 89 | iptables -t nat -A ISTIO_OUTPUT -j RETURN -m comment --comment "istio/bypass-default-outbound" 90 | else 91 | iptables -t nat -A ISTIO_OUTPUT -j ISTIO_REDIRECT -m comment --comment "istio/redirect-default-outbound" 92 | fi 93 | 94 | echo "successfully set up ip tables!" 95 | 96 | exit 0 -------------------------------------------------------------------------------- /test/iptable/tproxy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/ash 2 | iptables -t mangle -N DIVERT 3 | iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT 4 | iptables -t mangle -A DIVERT -j MARK --set-mark 1 5 | iptables -t mangle -A DIVERT -j ACCEPT 6 | ip rule add fwmark 1 lookup 100 7 | ip route add local 0.0.0.0/0 dev lo table 100 -------------------------------------------------------------------------------- /test/services/http.js: -------------------------------------------------------------------------------- 1 | const http = require('http'); 2 | 3 | 4 | const port = process.argv[2] || 8000; 5 | 6 | console.log('listening to port',port); 7 | 8 | 9 | http.createServer( async (request, response) => { 10 | 11 | response.writeHead(200, {'Content-type':'text/plan'}); 12 | response.write(`${port}`); 13 | response.end( ); 14 | }).listen(port); 15 | 16 | --------------------------------------------------------------------------------