Skip to content

Commit

Permalink
Merge pull request #22 from andrewshan/main
Browse files Browse the repository at this point in the history
feat:支持环境变量设置服务名和命名空间
  • Loading branch information
andrewshan authored Sep 1, 2022
2 parents 51f6af9 + b36717e commit 97d2ee7
Show file tree
Hide file tree
Showing 5 changed files with 216 additions and 39 deletions.
13 changes: 6 additions & 7 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,18 @@ RUN set -ex \
&& rm -rf polaris-cpp

RUN set -ex \
&& mkdir -p /server \
&& mkdir -p /etc/nginx \
&& cd /build/third_party \
&& ngx_file_name=nginx-1.23.1 \
&& curl http://nginx.org/download/"$ngx_file_name".tar.gz -o "$ngx_file_name".tar.gz \
&& tar xf "$ngx_file_name".tar.gz \
&& cp nginx/make "$ngx_file_name"/auto/ \
&& cp nginx/nginx.conf "$ngx_file_name"/conf/ \
&& chmod +x "$ngx_file_name"/configure \
&& cd "$ngx_file_name" \
&& ./configure --prefix=/server --add-module=../../source/nginx_polaris_limit_module --add-module=../polaris_client --with-stream --with-cpp=g++ \
&& ./configure --prefix=/etc/nginx --add-module=../../source/nginx_polaris_limit_module --add-module=../polaris_client --with-stream --with-cpp=g++ \
&& make \
&& make install
&& make install \
&& ln -s /etc/nginx/sbin/nginx /usr/local/bin/nginx


ENV PATH=/server/sbin:$PATH

CMD ["nginx", "-g", "daemon off;"]
CMD ["nginx", "-g", "daemon off;", "-c", "/etc/nginx/conf/nginx.conf"]
1 change: 1 addition & 0 deletions build/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ rm -rf "$ngx_file_name"
curl http://nginx.org/download/"$ngx_file_name".tar.gz -o "$ngx_file_name".tar.gz
tar xf "$ngx_file_name".tar.gz
cp nginx/make "$ngx_file_name"/auto/
cp nginx/nginx.conf "$ngx_file_name"/conf/

pushd polaris-cpp
make
Expand Down
110 changes: 80 additions & 30 deletions source/nginx_polaris_limit_module/ngx_http_polaris_limit_module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@
#include "ngx_http_polaris_limit_module.h"

typedef struct {
ngx_str_t service_namespace; // 命名空间

ngx_str_t service_name; // 服务名
ngx_int_t enable; // 是否启用限流

ngx_int_t status_code; // 返回码

std::string service_namespace; // 命名空间

std::string service_name; // 服务名

} ngx_http_polaris_limit_conf_t;

static ngx_int_t ngx_http_polaris_limit_handler(ngx_http_request_t *r);
Expand Down Expand Up @@ -82,20 +84,18 @@ static ngx_int_t ngx_http_polaris_limit_handler(ngx_http_request_t *r) {
std::map<std::string, std::string> labels;
const std::set<std::string> *label_keys;

ngx_str_t service_namespace_str;
ngx_str_t service_name_str;
plcf = reinterpret_cast<ngx_http_polaris_limit_conf_t *>(
ngx_http_get_module_loc_conf(r, ngx_http_polaris_limit_module));
service_namespace_str = plcf->service_namespace;
service_name_str =plcf->service_name;

if (plcf->enable == 0) {
return NGX_DECLINED;
}
polaris::LimitApi* limit_api = Limit_API_SINGLETON.GetLimitApi();
if (NULL == limit_api) {
return NGX_OK;
return NGX_DECLINED;
}
std::string service_namespace(reinterpret_cast<char *>(service_namespace_str.data), service_namespace_str.len);
std::string service_name(reinterpret_cast<char *>(service_name_str.data), service_name_str.len);
polaris::ServiceKey serviceKey = {service_namespace, service_name};

polaris::ServiceKey serviceKey = {plcf->service_namespace, plcf->service_name};
std::string method = std::string(reinterpret_cast<char *>(r->uri.data), r->uri.len);
ret = Limit_API_SINGLETON.GetLimitApi()->FetchRuleLabelKeys(serviceKey, label_keys);

Expand All @@ -105,22 +105,22 @@ static ngx_int_t ngx_http_polaris_limit_handler(ngx_http_request_t *r) {
}
ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "[PolarisRateLimiting] FetchRuleLabelKeys return is: %d, labels %s", ret, labels_key_str.c_str());
if (ret == polaris::kReturnTimeout) {
return NGX_DECLINED; // 拉取labelkey超时,不限流
return NGX_DECLINED; // 拉取labelkey超时,不限流
} else if (ret != polaris::kReturnOk) {
return plcf->status_code; // 返回为限流配置的状态码
}

get_labels_from_request(r, label_keys, labels); // 从http 请求中获取labels
std::string uri(reinterpret_cast<char *>(r->uri.data), r->uri.len);
quota_request.SetServiceNamespace(service_namespace); // 设置限流规则对应服务的命名空间
quota_request.SetServiceName(service_name); // 设置限流规则对应的服务名
quota_request.SetServiceNamespace(plcf->service_namespace); // 设置限流规则对应服务的命名空间
quota_request.SetServiceName(plcf->service_name); // 设置限流规则对应的服务名
quota_request.SetMethod(uri);
quota_request.SetLabels(labels); // 设置label用于匹配限流规则

std::string labels_values_str;
join_map_str(r->connection->log, labels, labels_values_str);
ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"[PolarisRateLimiting] quota_request namespace %s, service %s, method %s, labels %s", service_namespace.c_str(), service_name.c_str(), uri.c_str(), labels_values_str.c_str());
"[PolarisRateLimiting] quota_request namespace %s, service %s, method %s, labels %s", plcf->service_namespace.c_str(), plcf->service_name.c_str(), uri.c_str(), labels_values_str.c_str());

ret = Limit_API_SINGLETON.GetLimitApi()->GetQuota(quota_request, result);

Expand Down Expand Up @@ -160,6 +160,10 @@ static void join_map_str(const ngx_log_t *log, const std::map<std::string, std::
}
}

bool string2bool(const std::string & v) {
return !v.empty () && (strcasecmp (v.c_str (), "true") == 0 || atoi (v.c_str ()) != 0);
}

/* 读取配置参数 polaris_limit */
static char *ngx_http_polaris_limit_conf_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {
ngx_http_polaris_limit_conf_t *plcf;
Expand All @@ -168,34 +172,80 @@ static char *ngx_http_polaris_limit_conf_set(ngx_conf_t *cf, ngx_command_t *cmd,
plcf = reinterpret_cast<ngx_http_polaris_limit_conf_t *>(conf);
value = reinterpret_cast<ngx_str_t *>(cf->args->elts);

bool has_namespace = false;
bool has_service = false;
bool has_enable = false;

for (i = 1; i < cf->args->nelts; i++) {
if (ngx_strncmp(value[i].data, KEY_NAMESPACE, KEY_NAMESPACE_SIZE) == 0) {
size_t ns_size = value[i].len - KEY_NAMESPACE_SIZE;
if (ns_size <= 0) {
ngx_str_t namespace_str = {DEFAULT_NAMESPACE_SIZE, (u_char *)DEFAULT_NAMESPACE};
plcf->service_namespace = namespace_str;
ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "[PolarisRateLimiting] nginx namespace not set, use 'default' as namespace");
} else {
if (ns_size > 0) {
ngx_str_t namespace_str = {value[i].len - KEY_NAMESPACE_SIZE, &value[i].data[KEY_NAMESPACE_SIZE]};
plcf->service_namespace = namespace_str;
ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "[PolarisRateLimiting] use %V as nginx namespace", &namespace_str);
plcf->service_namespace = std::string(reinterpret_cast<char *>(namespace_str.data), namespace_str.len);
has_namespace = true;
}
continue;
}

if (ngx_strncmp(value[i].data, KEY_SERVICE_NAME, KEY_SERVICE_NAME_SIZE) == 0) {
ngx_str_t svc_name_str = {value[i].len - KEY_SERVICE_NAME_SIZE, &value[i].data[KEY_SERVICE_NAME_SIZE]};
plcf->service_name = svc_name_str;
if (plcf->service_name.len <= 0) {
plcf->service_name.data = NULL;
plcf->service_name.len = 0;
ngx_conf_log_error(NGX_LOG_ERR, cf, 0, "[PolarisRateLimiting] service name not set");
return static_cast<char *>(NGX_CONF_ERROR);
} else {
ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "[PolarisRateLimiting] use %V as service", &svc_name_str);
size_t svc_size = value[i].len - KEY_SERVICE_NAME_SIZE;
if (svc_size > 0) {
ngx_str_t svc_name_str = {value[i].len - KEY_SERVICE_NAME_SIZE, &value[i].data[KEY_SERVICE_NAME_SIZE]};
ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "[PolarisRateLimiting] use %V as nginx service name", &svc_name_str);
plcf->service_name = std::string(reinterpret_cast<char *>(svc_name_str.data), svc_name_str.len);
has_service = true;
}
continue;
}

if (ngx_strncmp(value[i].data, KEY_ENABLE, KEY_ENABLE_SIZE) == 0) {
size_t enable_size = value[i].len - KEY_ENABLE_SIZE;
if (enable_size > 0) {
ngx_str_t enable_str = {value[i].len - KEY_ENABLE_SIZE, &value[i].data[KEY_ENABLE_SIZE]};
ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "[PolarisRateLimiting] use %V as nginx ratelimit enable value", &enable_str);
std::string enable_str_value = std::string(reinterpret_cast<char *>(enable_str.data), enable_str.len);
if (string2bool(enable_str_value)) {
plcf->enable = 1;
} else {
plcf->enable = 0;
}
ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "[PolarisRateLimiting] use %V as nginx ratelimit enable", plcf->enable);
has_enable = true;
}
continue;
}

if (!has_namespace) {
char *namespace_env_value = getenv(ENV_NAMESPACE.c_str());
if (NULL != namespace_env_value) {
plcf->service_namespace = std::string(namespace_env_value);
} else {
plcf->service_namespace = DEFAULT_NAMESPACE;
}
ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "[PolarisRateLimiting] use %s as nginx namespace", plcf->service_namespace.c_str());
}

if (!has_service) {
char *service_env_value = getenv(ENV_SERVICE.c_str());
if (NULL != service_env_value) {
plcf->service_name = std::string(service_env_value);
} else {
plcf->service_name = DEFAULT_SERVICE;
}
ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "[PolarisRateLimiting] use %s as nginx service name", plcf->service_name.c_str());
}

if (!has_enable) {
char *enable_env_value = getenv(ENV_RATELIMIT_ENABLE.c_str());
if (NULL != enable_env_value) {
std::string enable_str = std::string(enable_env_value);
plcf->enable = string2bool(enable_str) ? 1 : 0;
} else {
plcf->enable = 0;
}
ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "[PolarisRateLimiting] use %V as nginx ratelimit enable", plcf->enable);
}
}

return static_cast<char *>(NGX_CONF_OK);
Expand Down
13 changes: 11 additions & 2 deletions source/nginx_polaris_limit_module/ngx_http_polaris_limit_module.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,22 @@ extern "C" {
#include <string>
#include <unistd.h>
#include <fstream>
#include <cstring>
#include <cstdlib>

static const char KEY_ENABLE[] = "enable";
static const uint32_t KEY_ENABLE_SIZE = sizeof(KEY_ENABLE) - 1;
static const char KEY_NAMESPACE[] = "namespace=";
static const uint32_t KEY_NAMESPACE_SIZE = sizeof(KEY_NAMESPACE) - 1;
static const char KEY_SERVICE_NAME[] = "service=";
static const uint32_t KEY_SERVICE_NAME_SIZE = sizeof(KEY_SERVICE_NAME) - 1;
static const char DEFAULT_NAMESPACE[] = "default";
static const uint32_t DEFAULT_NAMESPACE_SIZE = sizeof(DEFAULT_NAMESPACE) - 1;

static const std::string ENV_NAMESPACE = "polaris.nginx.namespace";
static const std::string ENV_SERVICE = "polaris.nginx.service";
static const std::string ENV_RATELIMIT_ENABLE = "polaris.nginx.ratelimit.enable";

static const std::string DEFAULT_NAMESPACE = "default";
static const std::string DEFAULT_SERVICE = "nginx-gateway";

static const std::string LABEL_KEY_METHOD = "$method";
static const std::string LABEL_KEY_HEADER = "$header.";
Expand Down
118 changes: 118 additions & 0 deletions third_party/nginx/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@

#user nobody;
worker_processes 1;

#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;

#pid logs/nginx.pid;


events {
worker_connections 1024;
}


http {
include mime.types;
default_type application/octet-stream;

#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';

#access_log logs/access.log main;

sendfile on;
#tcp_nopush on;

#keepalive_timeout 0;
keepalive_timeout 65;

#gzip on;

server {
listen 80;
server_name localhost;

#charset koi8-r;

#access_log logs/host.access.log main;

location / {
polaris_rate_limiting;
root html;
index index.html index.htm;
}

#error_page 404 /404.html;

# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}

# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}

# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}


# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;

# location / {
# root html;
# index index.html index.htm;
# }
#}


# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;

# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;

# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;

# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;

# location / {
# root html;
# index index.html index.htm;
# }
#}

}

0 comments on commit 97d2ee7

Please sign in to comment.