Skip to content

Commit e92c3ce

Browse files
5.1.3 (#70)
* 20240917-01 dev Moesif integration * 20240917-01 Added API visibility integration with Moesif Postman collection updated
1 parent ee9d2f6 commit e92c3ce

File tree

11 files changed

+247
-91
lines changed

11 files changed

+247
-91
lines changed

FEATURES.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ Declaration path `.declaration.http.servers[].locations[].apigateway` defines th
6060
- `developer_portal.type` - developer portal type. `redocly` and `backstage` are currently supported
6161
- `developer_portal.redocly.*` - Redocly-based developer portal parameters. See the [Postman collection](/contrib/postman)
6262
- `developer_portal.backstage.*` - Backstage-based developer portal parameters. See the [Postman collection](/contrib/postman)
63+
- `visibility[]` - API Gateway visibility
64+
- `visibility[].enabled` - enable/disable API gateway visibility
65+
- `visibility[].type` - visibility integration type. `moesif` is currently supported
66+
- `visibility[].moesif.*` - Moesif visibility parameters. See the [Postman collection](/contrib/postman)
6367
- `authentication` - optional, used to enforce authentication at the API Gateway level
6468
- `authentication.client[]` - authentication profile names
6569
- `authentication.enforceOnPaths` - if set to `true` authentication is enforced on all API endpoints listed under `authentication.paths`. if set to `false` authentication is enforced on all API endpoints but those listed under `authentication.paths`
@@ -80,6 +84,13 @@ See the [Postman collection](/contrib/) for usage examples
8084
| Redocly | X | X | X | Developer portal published by NGINX Plus |
8185
| Backstage.io | | X | X | Backstage YAML manifest generated |
8286

87+
### NGINX API Gateway use case - Visibility
88+
89+
| Type | API v4.2 | API v5.0 | API v5.1 | Notes |
90+
|--------------|----------|----------|----------|-----------------------------------------------------------------------------------------------|
91+
| Moesif | | | X | Integration with Moesif - see https://www.moesif.com/docs/server-integration/nginx-openresty/ |
92+
93+
8394
### Client authentication
8495

8596
| Type | Description | API v4.2 | API v5.0 | API v5.1 | Notes |

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ stateDiagram-v2
5454
DEVP: Developer Portal Service
5555
OUTPUT: Output
5656
REDIS: Redis
57+
3RDPARTY: 3rd Party integrations
5758
5859
DevOps --> Pipeline
5960
Pipeline --> INPUT
@@ -62,6 +63,8 @@ stateDiagram-v2
6263
NDAPI --> OUTPUT
6364
NDAPI --> SOT
6465
SOT --> NDAPI
66+
NDAPI --> 3RDPARTY
67+
3RDPARTY --> NDAPI
6568
NDAPI --> REDIS
6669
REDIS --> NDAPI
6770
OUTPUT --> NIM

contrib/postman/NGINX Declarative API.postman_collection.json

Lines changed: 105 additions & 85 deletions
Large diffs are not rendered by default.

etc/config.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ mimetypes = "nginx-conf/mime.types"
1414

1515
httpconf = "http.tmpl"
1616
apigwconf = "apigateway.tmpl"
17+
visibility_root = "visibility"
1718
streamconf = "stream.tmpl"
1819
configmap = "configmap.tmpl"
1920

@@ -54,6 +55,7 @@ nginx_conf = '/etc/nginx/nginx.conf'
5455
config_dir = '/etc/nginx'
5556
certs_dir = '/etc/nginx/ssl'
5657
apigw_dir = '/etc/nginx/apigateway'
58+
visibility_dir = '/etc/nginx/visibility'
5759
devportal_dir = '/etc/nginx/devportal'
5860
auth_client_dir = '/etc/nginx/authn/client'
5961
auth_server_dir = '/etc/nginx/authn/server'

src/V5_1_CreateConfig.py

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,52 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn
444444
"message": {"status_code": status, "message":
445445
{"code": status, "content": f"invalid server authentication profile [{authServerProfile['profile']}] in location [{loc['uri']}]"}}}
446446

447+
# API Gateway visualization integrations
448+
apiGwVisibilityIntegrations = {}
449+
450+
if loc['apigateway'] and loc['apigateway']['visibility']:
451+
visibility_integrations = loc['apigateway']['visibility']
452+
for i in range(len(visibility_integrations)):
453+
vis = visibility_integrations[i]
454+
455+
if vis['enabled'] == True:
456+
apiGwVisibilityIntegrations[ vis['type'] ] = True
457+
458+
if vis['type'].lower() == 'moesif':
459+
# Moesif integration
460+
461+
# Add the rendered Moesif visibility configuration snippet as a config file in the staged configuration - HTTP context
462+
templateName = NcgConfig.config['templates'][
463+
'visibility_root'] + "/moesif/http.tmpl"
464+
renderedMoesifHTTP = j2_env.get_template(templateName).render(
465+
vis=vis, loc=loc, ncgconfig=NcgConfig.config)
466+
467+
b64renderedMoesifHTTP = base64.b64encode(
468+
bytes(renderedMoesifHTTP, 'utf-8')).decode(
469+
'utf-8')
470+
moesifHTTPConfigFile = {'contents': b64renderedMoesifHTTP,
471+
'name': NcgConfig.config['nms'][
472+
'visibility_dir'] +
473+
loc['uri'] + "-moesif-http.conf"}
474+
475+
auxFiles['files'].append(moesifHTTPConfigFile)
476+
477+
# Add the rendered Moesif visibility configuration snippet as a config file in the staged configuration - server context
478+
templateName = NcgConfig.config['templates'][
479+
'visibility_root'] + "/moesif/server.tmpl"
480+
renderedMoesifServer = j2_env.get_template(templateName).render(
481+
vis=vis, loc=loc, ncgconfig=NcgConfig.config)
482+
483+
b64renderedMoesifServer = base64.b64encode(
484+
bytes(renderedMoesifServer, 'utf-8')).decode(
485+
'utf-8')
486+
moesifServerConfigFile = {'contents': b64renderedMoesifServer,
487+
'name': NcgConfig.config['nms'][
488+
'visibility_dir'] +
489+
loc['uri'] + "-moesif-server.conf"}
490+
491+
auxFiles['files'].append(moesifServerConfigFile)
492+
447493
# API Gateway provisioning
448494
if loc['apigateway'] and loc['apigateway']['api_gateway'] and loc['apigateway']['api_gateway']['enabled'] and loc['apigateway']['api_gateway']['enabled'] == True:
449495
openApiAuthProfile = loc['apigateway']['openapi_schema']['authentication']
@@ -458,7 +504,7 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn
458504
# API Gateway configuration template rendering
459505
if apiGatewayConfigDeclaration:
460506
apiGatewaySnippet = j2_env.get_template(NcgConfig.config['templates']['apigwconf']).render(
461-
declaration=apiGatewayConfigDeclaration, ncgconfig=NcgConfig.config)
507+
declaration=apiGatewayConfigDeclaration, enabledVisibility=apiGwVisibilityIntegrations, ncgconfig=NcgConfig.config)
462508
apiGatewaySnippetb64 = base64.b64encode(bytes(apiGatewaySnippet, 'utf-8')).decode('utf-8')
463509

464510
newAuxFile = {'contents': apiGatewaySnippetb64, 'name': NcgConfig.config['nms']['apigw_dir'] +
@@ -485,14 +531,14 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn
485531
loc['apigateway']['developer_portal']['redocly']['uri']}
486532
auxFiles['files'].append(newAuxFile)
487533

534+
### / Redocly developer portal - Add optional API Developer portal HTML files
488535
elif loc['apigateway']['developer_portal']['type'].lower() == 'backstage':
489536
### Backstage developer portal - Create Kubernetes Backstage manifest
490537
backstageManifest = j2_env.get_template(f"{NcgConfig.config['templates']['devportal_root']}/backstage.tmpl").render(
491538
declaration=loc['apigateway']['developer_portal']['backstage'], openAPISchema = v5_1.MiscUtils.json_to_yaml(openAPISchemaJSON), ncgconfig=NcgConfig.config)
492539

493540
extraOutputManifests.append(backstageManifest)
494-
495-
### / Backstage developer portal - Create Kubernetes Backstage manifest
541+
### / Backstage developer portal - Create Kubernetes Backstage manifest
496542

497543
# Check rate limit profile name validity
498544
if loc['rate_limit'] is not None:

src/V5_1_NginxConfigDeclaration.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,10 +831,40 @@ def check_type(self) -> 'DeveloperPortal':
831831
return self
832832

833833

834+
class Visibility_Moesif(BaseModel, extra="forbid"):
835+
application_id: str = ""
836+
plugin_path: Optional[str] = "/usr/local/share/lua/5.1/resty/moesif"
837+
838+
839+
class Visibility(BaseModel, extra="forbid"):
840+
enabled: Optional[bool] = False
841+
type: str = ""
842+
moesif: Optional[Visibility_Moesif] = {}
843+
844+
@model_validator(mode='after')
845+
def check_type(self) -> 'Visibility':
846+
_enabled, _type, _moesif = self.enabled, self.type, self.moesif
847+
848+
valid = ['moesif']
849+
850+
if _enabled == True and _type not in valid:
851+
raise ValueError(f"Invalid visibility type [{_type}] must be one of {str(valid)}")
852+
853+
isError = False
854+
855+
if _type == 'moesif' and not _moesif:
856+
isError = True
857+
858+
if isError:
859+
raise ValueError(f"Missing visibility data for type [{_type}]")
860+
861+
return self
862+
834863
class APIGateway(BaseModel, extra="forbid"):
835864
openapi_schema: Optional[ObjectFromSourceOfTruth] = {}
836865
api_gateway: Optional[API_Gateway] = {}
837866
developer_portal: Optional[DeveloperPortal] = {}
867+
visibility: Optional[List[Visibility]] = []
838868
rate_limit: Optional[List[RateLimitApiGw]] = []
839869
authentication: Optional[APIGatewayAuthentication] = {}
840870
authorization: Optional[List[APIGatewayAuthorization]] = []

src/v5_1/NGINXOneOutput.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def NGINXOneOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpCo
3838
b64StreamConf: str,configFiles = {}, auxFiles = {},
3939
runfromautosync: bool = False,
4040
configUid: str = ""):
41-
# NGINX Instance Manager Staged Configuration publish
41+
# NGINX One Cloud Console Staged Configuration publish
4242

4343
nOneToken = v5_1.MiscUtils.getDictKey(d, 'output.nginxone.token')
4444
nOneConfigSyncGroup = v5_1.MiscUtils.getDictKey(d, 'output.nginxone.configsyncgroup')
@@ -213,7 +213,7 @@ def NGINXOneOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpCo
213213
#
214214
#### / NGINX App Protect policies support
215215

216-
### Publish staged config to instance group
216+
### Publish staged config to config sync group
217217
r = requests.put(url=f'{nOneUrl}/api/nginx/one/namespaces/{nOneNamespace}/config-sync-groups/{igUid}/config',
218218
data=json.dumps(stagedConfig),
219219
headers={'Content-Type': 'application/json', "Authorization": f"Bearer APIToken {nOneToken}"},

templates/v5.1/apigateway.tmpl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
# Strip base URI: {{ declaration.location.apigateway.api_gateway.strip_uri }}
1919
# Destination server: {{ destination_server }}
2020

21+
{% for v in enabledVisibility %}
22+
include "{{ ncgconfig.nms.visibility_dir }}{{ declaration.location.uri }}-{{ v }}-server.conf";
23+
{% endfor %}
24+
2125
{% if declaration.paths -%}
2226
{% for path in declaration.paths %}
2327
location {% if '{' not in path.path %}={% else %}~{% endif %} {{ declaration.location.uri }}{{ path.path | regex_replace('{(.*?)}','(.*)') }} {

templates/v5.1/http.tmpl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ include "{{ ncgconfig.nms.authz_client_dir }}/{{ authzprofile.name | replace(" "
4949

5050

5151
{# --- Upstreams section --- #}
52+
# Upstreams
5253
{% if declaration.upstreams %}
5354
{% for u in declaration.upstreams %}
5455
{% if u.name %}
@@ -58,13 +59,17 @@ include "{{ ncgconfig.nms.upstream_http_dir }}/{{ u.name | replace(' ', '_') }}.
5859
{% endif %}
5960

6061
{# --- Rate limit section --- #}
61-
62+
# Rate limiting zones
6263
{% if declaration.rate_limit %}
6364
{% for rl in declaration.rate_limit %}
6465
limit_req_zone {{ rl.key }} zone={{ rl.name }}:{{ rl.size }} rate={{ rl.rate }};
6566
{% endfor %}
6667
{% endif %}
6768

69+
{# --- Visibility integration section --- #}
70+
# Visibility integrations
71+
include "{{ ncgconfig.nms.visibility_dir }}/*-http.conf";
72+
6873
{# --- Server section for NGINX Plus API --- #}
6974

7075
{% if declaration.nginx_plus_api %}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Moesif integration - https://www.moesif.com/docs/server-integration/nginx-openresty/
2+
# URI: {{ loc.uri }}
3+
# application ID: {{ vis.moesif.application_id }}
4+
5+
lua_shared_dict moesif_conf 5m;
6+
7+
init_by_lua_block {
8+
local config = ngx.shared.moesif_conf;
9+
config:set("application_id", "{{ vis.moesif.application_id }}")
10+
}
11+
12+
lua_package_cpath ";;${prefix}?.so;${prefix}src/?.so;/usr/share/lua/5.1/lua/resty/moesif/?.so;/usr/share/lua/5.1/?.so;/usr/lib64/lua/5.1/?.so;/usr/lib/lua/5.1/?.so;/usr/local/openresty/luajit/share/lua/5.1/lua/resty?.so;/usr/local/share/lua/5.1/resty/moesif/?.so;{{ vis.moesif.plugin_path }}/?.so";
13+
lua_package_path ";;${prefix}?.lua;${prefix}src/?.lua;/usr/share/lua/5.1/lua/resty/moesif/?.lua;/usr/share/lua/5.1/?.lua;/usr/lib64/lua/5.1/?.lua;/usr/lib/lua/5.1/?.lua;/usr/local/openresty/luajit/share/lua/5.1/lua/resty?.lua;/usr/local/share/lua/5.1/resty/moesif/?.lua;{{ vis.moesif.plugin_path }}/?.lua";
14+

0 commit comments

Comments
 (0)