Add posibility to set rate limiting to locations

Add possibility to override rate limits to custom location
on ngix proxy.

fixes-bug: PROD-36891
Change-Id: I5668818b691089304cd7242a1c795d9c6109ca27
diff --git a/README.rst b/README.rst
index aa9875f..d7f004b 100644
--- a/README.rst
+++ b/README.rst
@@ -460,6 +460,36 @@
                   burst: 5
                   enabled: true
 
+To apply request limiting to particular location of particular site  `limit` should be
+applied on location level. Pay attention that location level overrides site level, 
+Two methods are supported:
+  - By IP
+  - By http requst method (get, post ...)
+for example:
+
+.. code-block:: yaml
+
+    nginx:
+      server:
+        site:
+          nginx_proxy_openstack_api_keystone:
+            location:
+              /some_location/:
+                limit:
+                  enabled: true
+                  methods:
+                    ip:
+                      enabled: True
+                    get:
+                      enabled: True
+                      rate: 120r/s
+                      burst: 600
+                      size: 20m
+                      nodelay: True
+                    post:
+                      enabled: True
+                      rate: 50r/m
+                      burst: 80
 
 Use `ngx_http_limit_conn_module` module that is used to set the shared memory
 zone and the maximum allowed number of connections for a given key value.
diff --git a/nginx/files/_limit.conf b/nginx/files/_limit.conf
index e0ff102..b60406b 100644
--- a/nginx/files/_limit.conf
+++ b/nginx/files/_limit.conf
@@ -29,3 +29,41 @@
 {%-   endfor %}
 
 {%- endif %}
+
+  {%- set location = {} %}
+  {%- if site.get('location') %}
+    {%- do location.update(site.location) %}
+    {%- for path, location in location.items() %}
+      {%- if location.limit is defined %}
+      {%- if location.get('limit', {}).get('enabled', False) and location.limit.methods is defined %}
+        {%- if location.limit.methods.ip is defined and location.limit.methods.get('ip').get('enabled',False) %}
+      # Create whitelist for ip addresses
+geo $ip_{{ site_name }}_{{ path|replace('/','_') }} {
+    default "enforce";
+  {%- for ip in location.limit.methods.ip.get('ip_whitelist', []) %}
+    {{ ip }} "whitelist";
+  {%- endfor %}
+}
+      # First, map all whitelisted IP's to the request query
+map $ip_{{ site_name }}_{{ path|replace('/','_') }} $limit_{{ site_name }}_{{ path|replace('/','_') }} {
+    default {{ location.limit.methods.ip.get('query', '$binary_remote_addr') }};
+    "whitelist" "";
+}
+
+limit_req_zone $limit_{{ site_name }}_{{ path|replace('/','_') }} zone=ip_{{ site_name }}_{{ path|replace('/','_') }}:{{ location.limit.methods.ip.get('size', '10m') }} rate={{ location.limit.methods.ip.get('rate','10r/s') }};
+      {%- endif %}
+
+{%- for method, method_data in location.limit.methods.items() %}
+{%- if method != 'ip' %}
+map $request_method $limit_{{ method }}_{{ site_name }}_{{ path|replace('/','_') }} {
+    default "";
+    {{ method|upper }} "limit_{{ method }}";
+}
+limit_req_zone $limit_{{ method }}_{{ site_name }}_{{ path|replace('/','_') }} zone={{ method }}_{{ site_name }}_{{ path|replace('/','_') }}:{{ location.limit.methods.get(method,{}).get('size', '10m') }} rate={{ location.limit.methods.get(method,{}).get('rate','10r/s') }};
+{%- endif %}
+{%- endfor %}
+      {%- endif %}
+      {%- endif %}
+    {%- endfor %}
+  {%- endif %}
+
diff --git a/nginx/files/proxy.conf b/nginx/files/proxy.conf
index 8d57fd8..7aac4a4 100644
--- a/nginx/files/proxy.conf
+++ b/nginx/files/proxy.conf
@@ -146,11 +146,18 @@
       {# The approach below is deprecated, as it was limited funtionality #}
       {# compare to flexibility that nginx provide. site:limit_req_module:limit_req shall be used instead. #}
 
-      {%- if site.get('limit', {}).get('enabled', False) %}
+      {%- if location.limit is defined  and location.limit.methods is defined %}
+        {%- for method, method_data in location.limit.methods.items() %}
+          {%- if method_data.get('enabled', False) %}
+      limit_req zone={{ method }}_{{ site_name+'_'+path|replace('/','_') }}{% if method_data.get('burst', False) %} burst={{ method_data.burst }}{% endif %}{% if method_data.get('nodelay', False) %} nodelay{% endif %};
+          {%- endif %}
+        {%- endfor %}
+
+      {%- elif site.get('limit', {}).get('enabled', False) %}
       limit_req zone={{ site_name }}{% if site.limit.get('burst', False) %} burst={{ site.limit.burst }}{% endif %}{% if site.limit.get('nodelay', False) %} nodelay{% endif %};
-      {%-   for subfilter_name, subfilter in site.limit.get('subfilters', {}).items() %}
+        {%-   for subfilter_name, subfilter in site.limit.get('subfilters', {}).items() %}
       limit_req zone={{ site_name }}_{{ subfilter_name }}{% if subfilter.get('burst', False) %} burst={{ subfilter.burst }}{% endif %}{% if subfilter.get('nodelay', False) %} nodelay{% endif %};
-      {%-   endfor %}
+        {%-   endfor %}
       {%- endif %}
   }
 {%- endfor %}