Related
We are using Terraform to describe an AWS apiGw objects and Checkov to check our plan output. Originally we found we could not get Checkov to pass as it always failed on CKV2_AWS_4 "Ensure API Gateway stage have logging level defined as appropriate".
Since then we have tried using both the Checkov site example and the Terraform example in place of our production apiGw but these fail too. Link to Checkov example:-
https://docs.bridgecrew.io/docs/ensure-api-gateway-stage-have-logging-level-defined-as-appropiate
The notation for the Checkov test failing is:-
metadata:
id: "CKV2_AWS_4"
name: "Ensure API Gateway stage have logging level defined as appropriate"
category: "LOGGING"
definition:
and:
- resource_types:
- aws_api_gateway_stage
connected_resource_types:
- aws_api_gateway_method_settings
operator: exists
cond_type: connection
- or:
- cond_type: "attribute"
resource_types:
- "aws_api_gateway_method_settings"
attribute: "settings.logging_level"
operator: "equals"
value: "ERROR"
- cond_type: "attribute"
resource_types:
- "aws_api_gateway_method_settings"
attribute: "settings.logging_level"
operator: "equals"
value: "INFO"
- cond_type: "attribute"
resource_types:
- "aws_api_gateway_method_settings"
attribute: "settings.metrics_enabled"
operator: "equals"
value: true
- cond_type: filter
attribute: resource_type
value:
- aws_api_gateway_stage
operator: within
Here is our TF which is an expanded version of the Terraform apiGw example:-
data "aws_caller_identity" "current" {}
locals {
# The target account number
account_id = data.aws_caller_identity.current.account_id
# Local variable this is likely to be one of the following: development, nonproduction, production, feature/{name}.
name_suffix = terraform.workspace
}
resource "aws_api_gateway_rest_api" "example" {
body = jsonencode({
openapi = "3.0.1"
info = {
title = "example"
version = "1.0"
}
paths = {
"/path1" = {
get = {
x-amazon-apigateway-integration = {
httpMethod = "GET"
payloadFormatVersion = "1.0"
type = "HTTP_PROXY"
uri = "https://ip-ranges.amazonaws.com/ip-ranges.json"
}
}
}
}
})
name = "example"
}
resource "aws_api_gateway_deployment" "example" {
rest_api_id = aws_api_gateway_rest_api.example.id
triggers = {
redeployment = sha1(jsonencode(aws_api_gateway_rest_api.example.body))
}
lifecycle {
create_before_destroy = true
}
}
resource "aws_api_gateway_stage" "example" {
deployment_id = "${aws_api_gateway_deployment.example.id}"
rest_api_id = "${aws_api_gateway_rest_api.example.id}"
stage_name = "example"
cache_cluster_enabled = true
cache_cluster_size = 6.1
xray_tracing_enabled = true
access_log_settings {
destination_arn = aws_cloudwatch_log_group.transfer_apigw_log_group.arn
format = "$context.identity.sourceIp,$context.identity.caller,$context.identity.user,$context.requestTime,$context.httpMethod,$context.resourcePath,$context.protocol,$context.status,$context.responseLength,$context.requestId,$context.extendedRequestId"
}
}
resource "aws_api_gateway_method_settings" "all" {
rest_api_id = "${aws_api_gateway_rest_api.example.id}"
stage_name = "${aws_api_gateway_stage.example.stage_name}"
method_path = "*/*"
settings {
metrics_enabled = true
logging_level = "ERROR"
caching_enabled = true
}
}
resource "aws_api_gateway_method_settings" "path_specific" {
rest_api_id = aws_api_gateway_rest_api.example.id
stage_name = aws_api_gateway_stage.example.stage_name
method_path = "path1/GET"
settings {
metrics_enabled = true
logging_level = "INFO"
caching_enabled = true
}
}
resource "aws_cloudwatch_log_group" "transfer_apigw_log_group" {
name = "transfer_apigw_log_group-${var.region}-${local.name_suffix}"
retention_in_days = 30
kms_key_id = "alias/aws/apigateway"
}
When TF plan runs we get this result which Checkov reads:-
{
"format_version": "1.1",
"terraform_version": "1.2.7",
"planned_values": {
"root_module": {
"child_modules": [
{
"resources": [
{
"address": "module.api_gateway_uk.aws_api_gateway_deployment.example",
"mode": "managed",
"type": "aws_api_gateway_deployment",
"name": "example",
"provider_name": "registry.terraform.io/hashicorp/aws",
"schema_version": 0,
"values": {
"description": null,
"stage_description": null,
"stage_name": null,
"triggers": {
"redeployment": "145be397ea51cabb14595b0f0ace006017953f0a"
},
"variables": null
},
"sensitive_values": {
"triggers": {}
}
},
{
"address": "module.api_gateway_uk.aws_api_gateway_method_settings.all",
"mode": "managed",
"type": "aws_api_gateway_method_settings",
"name": "all",
"provider_name": "registry.terraform.io/hashicorp/aws",
"schema_version": 0,
"values": {
"method_path": "*/*",
"settings": [
{
"caching_enabled": true,
"logging_level": "ERROR",
"metrics_enabled": true,
"throttling_burst_limit": -1,
"throttling_rate_limit": -1
}
],
"stage_name": "example"
},
"sensitive_values": {
"settings": [
{}
]
}
},
{
"address": "module.api_gateway_uk.aws_api_gateway_method_settings.path_specific",
"mode": "managed",
"type": "aws_api_gateway_method_settings",
"name": "path_specific",
"provider_name": "registry.terraform.io/hashicorp/aws",
"schema_version": 0,
"values": {
"method_path": "path1/GET",
"settings": [
{
"caching_enabled": true,
"logging_level": "INFO",
"metrics_enabled": true,
"throttling_burst_limit": -1,
"throttling_rate_limit": -1
}
],
"stage_name": "example"
},
"sensitive_values": {
"settings": [
{}
]
}
},
{
"address": "module.api_gateway_uk.aws_api_gateway_rest_api.example",
"mode": "managed",
"type": "aws_api_gateway_rest_api",
"name": "example",
"provider_name": "registry.terraform.io/hashicorp/aws",
"schema_version": 0,
"values": {
"body": "{\"info\":{\"title\":\"example\",\"version\":\"1.0\"},\"openapi\":\"3.0.1\",\"paths\":{\"/path1\":{\"get\":{\"x-amazon-apigateway-integration\":{\"httpMethod\":\"GET\",\"payloadFormatVersion\":\"1.0\",\"type\":\"HTTP_PROXY\",\"uri\":\"https://ip-ranges.amazonaws.com/ip-ranges.json\"}}}}}",
"minimum_compression_size": -1,
"name": "example",
"parameters": null,
"put_rest_api_mode": null,
"tags": null
},
"sensitive_values": {
"binary_media_types": [],
"endpoint_configuration": [],
"tags_all": {}
}
},
{
"address": "module.api_gateway_uk.aws_api_gateway_stage.example",
"mode": "managed",
"type": "aws_api_gateway_stage",
"name": "example",
"provider_name": "registry.terraform.io/hashicorp/aws",
"schema_version": 0,
"values": {
"access_log_settings": [
{
"format": "$context.identity.sourceIp,$context.identity.caller,$context.identity.user,$context.requestTime,$context.httpMethod,$context.resourcePath,$context.protocol,$context.status,$context.responseLength,$context.requestId,$context.extendedRequestId"
}
],
"cache_cluster_enabled": true,
"cache_cluster_size": "6.1",
"canary_settings": [],
"client_certificate_id": null,
"description": null,
"documentation_version": null,
"stage_name": "example",
"tags": null,
"variables": null,
"xray_tracing_enabled": true
},
"sensitive_values": {
"access_log_settings": [
{}
],
"canary_settings": [],
"tags_all": {}
}
},
{
"address": "module.api_gateway_uk.aws_cloudwatch_log_group.transfer_apigw_log_group",
"mode": "managed",
"type": "aws_cloudwatch_log_group",
"name": "transfer_apigw_log_group",
"provider_name": "registry.terraform.io/hashicorp/aws",
"schema_version": 0,
"values": {
"kms_key_id": "alias/aws/apigateway",
"name": "transfer_apigw_log_group-uk-default",
"retention_in_days": 30,
"skip_destroy": false,
"tags": null
},
"sensitive_values": {
"tags_all": {}
}
}
],
"address": "module.api_gateway_uk"
}
<SNIP>
I'm wondering which rule is being broken in the Checkov test? Could it be the 'connection' between objects like the apiGw Stage and the rest api? I am not clear how the tf plan output shows connections between objects but the tf plan passes without any issues.
Thanks in advance.
Jon
Getting error while deploying App gateway waf_v2 with more then one listener. For single listner it is working fine.
Error :
{"code":"DeploymentFailed","message":"At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/DeployOperations for usage details.","details":[{"code":"BadRequest","message":"{\r\n "error": {\r\n "code": "ApplicationGatewayHttpListenersUsingSameFrontendPortAndFrontendIpConfig",\r\n "message": "Two Http Listeners of Application Gateway journal-listner and attachmentmgmt-listner are using the same Frontend Port /subscriptions/77585cb5-cc1b-47a6-b60d-4c1ec4b078fc/resourceGroups/drgr001appgatewaydevtest-au/providers/Microsoft.Network/applicationGateways/bo-appgw-waf-v2-entdev1/frontendPorts/frontendPorts and FrontendIpConfiguration /subscriptions/77585cb5-cc1b-47a6-b60d-4c1ec4b078fc/resourceGroups/drgr001appgatewaydevtest-au/providers/Microsoft.Network/applicationGateways/bo-appgw-waf-v2-entdev1/frontendIPConfigurations/PrivateFrontendIp.",\r\n "details": []\r\n }\r\n}"}]}
template code :
// Application Gateway
{
"name": "[parameters('applicationGatewayName')]",
"type": "Microsoft.Network/applicationGateways",
"apiVersion": "2020-03-01",
"location": "[parameters('location')]",
"zones": "[parameters('availabilityZones')]",
"properties": {
"sku": {
"name": "WAF_v2",
"tier": "WAF_v2",
"capacity": "[parameters('capacity')]"
},
"sslCertificates": [
{
"name": "[parameters('certName')]",
"properties": {
"data": "[parameters('certData')]",
"password": "[parameters('certPassword')]"
}
}
],
"gatewayIPConfigurations": [
{
"name": "gatewayIp",
"properties": {
"subnet": {
"id": "[variables('subnetRef')]"
}
}
}
],
"trustedRootCertificates": "[parameters('trustedRootCertificates')]",
"frontendIPConfigurations": [
{
"name": "PublicFrontendIp",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[parameters('publicIpResourceId')]"
}
}
},
{
"name": "PrivateFrontendIp",
"properties": {
"privateIPAddress": "[parameters('privateIPAddress')]",
"privateIPAllocationMethod": "Static",
"subnet": {
"id": "[variables('subnetRef')]"
}
}
}
],
"frontendPorts": [
{
"name": "frontendPorts",
"properties": {
"Port": 443
}
}
],
"backendAddressPools": "[parameters('backendAddressPools')]",
"probes": "[parameters('probes')]",
"copy": [
{
"name": "backendHttpSettingsCollection",
"count": "[length(parameters('backendHttpSettings'))]",
"input": {
"name": "[parameters('backendHttpSettings')[copyIndex('backendHttpSettingsCollection')].name]",
"properties": {
"port": 443,
"pickHostNameFromBackendAddress": true,
"protocol": "Https",
"probeEnabled": "[parameters('backendHttpSettings')[copyIndex('backendHttpSettingsCollection')].probeEnabled]",
"probe": {
"id": "[resourceId('Microsoft.Network/applicationGateways/probes', parameters('applicationGatewayName'), parameters('backendHttpSettings')[copyIndex('backendHttpSettingsCollection')].probe)]"
}
}
}
},
{
"name": "httpListeners",
"count": "[length(parameters('httpListeners'))]",
"input": {
"name": "[parameters('httpListeners')[copyIndex('httpListeners')].name]",
"properties": {
"protocol": "Https",
// Set hostname if it exists
"hostName": "[if(contains(parameters('httpListeners')[copyIndex('httpListeners')], 'hostName'), parameters('httpListeners')[copyIndex('httpListeners')].hostName, '')]",
"sslCertificate": {
"id": "[concat(variables('applicationGatewayId'), '/sslCertificates/',parameters('httpListeners')[copyIndex('httpListeners')].sslCertificateName)]"
},
"frontendIPConfiguration": {
"id": "[concat(variables('applicationGatewayId'), '/frontendIPConfigurations/PrivateFrontendIp')]"
},
"frontendPort": {
"id": "[concat(variables('applicationGatewayId'), '/frontendPorts/frontendPorts')]"
}
}
}
},
{
"name": "requestRoutingRules",
"count": "[length(parameters('requestRoutingRules'))]",
"input": {
"name": "[parameters('requestRoutingRules')[copyIndex('requestRoutingRules')].name]",
"properties": {
"ruleType": "Basic",
"backendAddressPool": {
"id": "[concat(variables('applicationGatewayId'), '/backendAddressPools/',parameters('requestRoutingRules')[copyIndex('requestRoutingRules')].backendpoolName)]"
},
"backendHttpSettings": {
"id": "[concat(variables('applicationGatewayId'), '/backendHttpSettingsCollection/',parameters('requestRoutingRules')[copyIndex('requestRoutingRules')].backendHttpSetting)]"
},
"httpListener": {
"id": "[concat(variables('applicationGatewayId'), '/httpListeners/',parameters('requestRoutingRules')[copyIndex('requestRoutingRules')].httpListener)]"
}
}
}
}
],
"redirectConfigurations": "[parameters('redirectConfigurations')]",
"enableHttp2": "[parameters('enableHttp2')]",
"webApplicationFirewallConfiguration": "[variables('webApplicationFirewallConfiguration')]",
"urlPathMaps": "[parameters('urlPathMaps')]",
"authenticationCertificates": "[parameters('authenticationCertificates')]",
"sslPolicy": {
"policyType": "Predefined",
"policyName": "AppGwSslPolicy20170401S"
},
"rewriteRuleSets": "[parameters('rewriteRuleSets')]"
}
}
Parameter used :
"backendHttpSettings": {
"value": [
{
"name": "https-attachment",
"probeEnabled": true,
"probe": "attachment-probe"
},
{
"name": "https-journal",
"probeEnabled": true,
"probe": "journal-probe"
}
]
},
"backendAddressPools": {
"value": [
{
"name": "AttachmentServicePool",
"properties": {
"backendAddresses": [
{
"fqdn": "attachmentmgmt-svc-api-dev-euw.aseentdev.sys.dom"
}
]
}
},
{
"name": "journalServicePool",
"properties": {
"backendAddresses": [
{
"fqdn": "journalmgmt-svc-api-dev-euw.aseentdev.sys.dom"
}
]
}
}
]
},
"availabilityZones": {
"value": [
1,
2
]
},
"probes": {
"value": [
{
"name": "attachment-probe",
"properties": {
"protocol": "Https",
"PickHostNameFromBackendHttpSettings": true,
"path": "/index.htm",
"interval": 5,
"timeout": 10,
"match": {
"statusCodes": [
200
],
"body": "SUCCESS"
}
}
},
{
"name": "journal-probe",
"properties": {
"protocol": "Https",
"PickHostNameFromBackendHttpSettings": true,
"path": "/index.htm",
"interval": 5,
"timeout": 10,
"match": {
"statusCodes": [
200
],
"body": "SUCCESS"
}
}
}
]
},
"httpListeners": {
"value": [
{
"name": "attachmentmgmt-listner",
"sslCertificateName": "abc"
},
{
"name": "journal-listner",
"sslCertificateName": "abc"
}
]
},
"urlPathMaps": {
"value": []
},
"requestRoutingRules": {
"value": [
{
"name": "attachment-routing-rule",
"backendpoolName": "AttachmentServicePool",
"backendHttpSetting": "https-attachment",
"httpListener": "attachmentmgmt-listner"
},
{
"name": "journal-routing-rule",
"backendpoolName": "journalServicePool",
"backendHttpSetting": "https-journal",
"httpListener": "journal-listner"
}
]
},
You can't create two basic listeners on the same port. Either use different ports or two different hostnames with Multi site listener.
change in parameter file with passing host name for httplistner worked fine.
"httpListeners": {
"value": [
{
"name": "listner1",
"sslCertificateName": "ABC",
"hostName": "wb.abc.dom"
},
{
"name": "listner2",
"sslCertificateName": "ABC",
"hostName": "wb1.abc.dom"
}
]
}
I am trying to configure Azure Application Gateway with Basic Rule. For my Frontend IP, I have created set DNS name to whatever.canadacentral.cloudapp.azure.com and uploaded a self-signed certificate. When I hit https:// everything works correctly however when I go to https://whatever.canadacentral.cloudapp.azure.com it returns 307 redirecting me to my backend pool https://whatever.azurewebsites.net/
Is this something to do with canadacentral.cloudapp.azure.com and I need to provide custom DNS?
Here's my template for Application Gateway:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"applicationGateways_ExampleDev_name": {
"defaultValue": "ExampleDev",
"type": "String"
},
"virtualNetworks_Ex_DEV_externalid": {
"defaultValue": "/subscriptions/xxx/resourceGroups/Example-Ex-DEV/providers/Microsoft.Network/virtualNetworks/Ex-DEV",
"type": "String"
},
"publicIPAddresses_ExampleDevIP_externalid": {
"defaultValue": "/subscriptions/xxx/resourceGroups/Example-Ex-DEV/providers/Microsoft.Network/publicIPAddresses/ExampleDevIP",
"type": "String"
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.Network/applicationGateways",
"apiVersion": "2019-09-01",
"name": "[parameters('applicationGateways_ExampleDev_name')]",
"location": "canadacentral",
"properties": {
"sku": {
"name": "WAF_v2",
"tier": "WAF_v2"
},
"gatewayIPConfigurations": [
{
"name": "appGatewayIpConfig",
"properties": {
"subnet": {
"id": "[concat(parameters('virtualNetworks_Ex_DEV_externalid'), '/subnets/default')]"
}
}
}
],
"sslCertificates": [
{
"name": "ApplicationGateway",
"properties": {}
}
],
"trustedRootCertificates": [],
"frontendIPConfigurations": [
{
"name": "appGwPublicFrontendIp",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[parameters('publicIPAddresses_ExampleDevIP_externalid')]"
}
}
}
],
"frontendPorts": [
{
"name": "port_80",
"properties": {
"port": 80
}
},
{
"name": "port_443",
"properties": {
"port": 443
}
}
],
"backendAddressPools": [
{
"name": "ExampleApiDev",
"properties": {
"backendAddresses": [
{
"fqdn": "Exampleapi-dev.azurewebsites.net"
}
]
}
},
{
"name": "ExampleAuthDev",
"properties": {
"backendAddresses": [
{
"fqdn": "Exampleauth-dev.azurewebsites.net"
}
]
}
},
{
"name": "ExampleAppDev",
"properties": {
"backendAddresses": [
{
"fqdn": "Exampleapp-dev.azurewebsites.net"
}
]
}
}
],
"backendHttpSettingsCollection": [
{
"name": "default",
"properties": {
"port": 80,
"protocol": "Http",
"cookieBasedAffinity": "Disabled",
"pickHostNameFromBackendAddress": true,
"affinityCookieName": "ApplicationGatewayAffinity",
"requestTimeout": 20,
"probe": {
"id": "[concat(resourceId('Microsoft.Network/applicationGateways', parameters('applicationGateways_ExampleDev_name')), '/probes/defaultxxx')]"
}
}
}
],
"httpListeners": [
{
"name": "public-https",
"properties": {
"frontendIPConfiguration": {
"id": "[concat(resourceId('Microsoft.Network/applicationGateways', parameters('applicationGateways_ExampleDev_name')), '/frontendIPConfigurations/appGwPublicFrontendIp')]"
},
"frontendPort": {
"id": "[concat(resourceId('Microsoft.Network/applicationGateways', parameters('applicationGateways_ExampleDev_name')), '/frontendPorts/port_443')]"
},
"protocol": "Https",
"sslCertificate": {
"id": "[concat(resourceId('Microsoft.Network/applicationGateways', parameters('applicationGateways_ExampleDev_name')), '/sslCertificates/ApplicationGateway')]"
},
"hostNames": [],
"requireServerNameIndication": false
}
}
],
"urlPathMaps": [],
"requestRoutingRules": [
{
"name": "basic",
"properties": {
"ruleType": "Basic",
"httpListener": {
"id": "[concat(resourceId('Microsoft.Network/applicationGateways', parameters('applicationGateways_ExampleDev_name')), '/httpListeners/public-https')]"
},
"backendAddressPool": {
"id": "[concat(resourceId('Microsoft.Network/applicationGateways', parameters('applicationGateways_ExampleDev_name')), '/backendAddressPools/ExampleApiDev')]"
},
"backendHttpSettings": {
"id": "[concat(resourceId('Microsoft.Network/applicationGateways', parameters('applicationGateways_ExampleDev_name')), '/backendHttpSettingsCollection/default')]"
}
}
}
],
"probes": [
{
"name": "default07a3e3ac-3c07-40f6-ad80-837f4cdd1009",
"properties": {
"protocol": "Http",
"path": "/swagger/index.html",
"interval": 30,
"timeout": 30,
"unhealthyThreshold": 3,
"pickHostNameFromBackendHttpSettings": true,
"minServers": 0,
"match": {
"statusCodes": [
"200-399"
]
}
}
}
],
"rewriteRuleSets": [],
"redirectConfigurations": [],
"webApplicationFirewallConfiguration": {
"enabled": true,
"firewallMode": "Prevention",
"ruleSetType": "OWASP",
"ruleSetVersion": "3.0",
"disabledRuleGroups": [],
"exclusions": [],
"requestBodyCheck": true,
"maxRequestBodySizeInKb": 128,
"fileUploadLimitInMb": 50
},
"enableHttp2": false,
"autoscaleConfiguration": {
"minCapacity": 0,
"maxCapacity": 2
}
}
}
]
}
In this case, for application gateway V2, you have two solutions from this document.
Rewrite the location header
Set the host name in the location header to the application gateway's
domain name. To do this, create a rewrite rule with a condition that
evaluates if the location header in the response contains
azurewebsites.net. It must also perform an action to rewrite the
location header to have the application gateway's host name.
Use a custom domain name
In this way, you must own a custom domain and add custom domain in app servvice, see Map an existing custom DNS name to Azure App Service. You could follow this process:
The following ECS task definition is being rejected by Terraform during a plan. JSON validates and using the inline container_definitions works fine.
I've Googled and read some commentary that states TF has an issue with JSON objects, mostly related to nesting. I can get around this by placing the JSON into the container_definition directly in the resource block for the task definition, but I would prefer to stick it in a template file.
Error: Error running plan: 1 error(s) occurred:
* module.sonarqube.aws_ecs_task_definition.task: ECS Task Definition container_definitions is invalid: Error decoding JSON: json: cannot unmarshal string into Go struct field ContainerDefinition.Memory of type int64
JSON Document referenced in template_file:
{
"name": "sonarqube",
"image": "sonarqube:7.5-community",
"memory": "2048",
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "${log-group}",
"awslogs-region": "${region}",
"awslogs-stream-prefix": "ecs"
}
},
"portMappings": {
"hostPort": "9000",
"protocol": "tcp",
"containerPort": "9000"
},
"environment": [
{
"name": "sonar.jdbc.password",
"value": "${password}"
},
{
"name": "sonar.jdbc.url",
"value": "${url}/${extra_url}"
},
{
"name": "sonar.jdbc.username",
"value": "${username}"
}
]
}
Relevant TF Blocks:
data "template_file" "task-def" {
template = "${file("${path.module}/task-def.json")}"
vars = {
log-group = "/ecs/${var.cluster_name}-${var.name}"
region = "${var.region}"
url = "jdbc:postgresql://${var.rds_url}${var.extra_url}"
username = "${var.username}"
password = "${var.password}"
}
}
resource "aws_ecs_task_definition" "task" {
family = "${var.name}"
network_mode = "bridge"
cpu = "1024"
memory = "2048"
execution_role_arn = "${var.ecs-exec-role}"
container_definitions = "${data.template_file.task-def.rendered}"
}
```
Terraform expects Json in a bit dirrerent format. After you fix this it will work:
Memory size and port numbers should be integer, not string
Terraform wants "array with oblects", not a JSON "object"
Variable $extra_url was not imported in template_file.task-def
Fixed version of task-def.json, tested on terraform v0.11.13 and provider.aws v2.9.0:
[
{
"name": "sonarqube"
},
{
"image": "sonarqube:7.5-community"
},
{
"memory": 2048
},
{
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "tyu",
"awslogs-region": "tyu",
"awslogs-stream-prefix": "ecs"
}
}
},
{
"portMappings": [
{
"hostPort": 9000
},
{
"protocol": "tcp"
},
{
"containerPort": 9000
}
]
},
{
"environment": [
{
"name": "sonar.jdbc.password",
"value": "${password}"
},
{
"name": "sonar.jdbc.url",
"value": "${url}/${extra_url}"
},
{
"name": "sonar.jdbc.username",
"value": "${username}"
}
]
}
]
Fixed version of template_file.task-def:
data "template_file" "task-def" {
template = "${file("${path.module}/task-def.json")}"
vars = {
log-group = "/ecs/${var.cluster_name}-${var.name}"
region = "${var.region}"
url = "jdbc:postgresql://${var.rds_url}${var.extra_url}"
username = "${var.username}"
password = "${var.password}"
extra_url = "${var.extra_url}"
}
}
I'm learning node.js
I have an object like this-
environments=[{
"name": "test",
"resourceLimits": {
"cpu": { "min": 0.1, "max": 10 },
"target": {"targetName": "del", "env": "dev", "region": "us-east-1"},
"name": "test2",
"resourceLimits": {
"cpu": { "min": 0.1, "max": 10 },
"target": {"targetName": "bob", "env": "dev", "region": "us-east-1"}],
I am trying to find the name of environment where targetName=bob
If targetName existed outside the target object , i could have done
let myEnv = _.chain(environments).where({ targetName: "Bob" }).first().value();
//and print myEnv.name
However, the following is a synax error
let myEnv = _.chain(environments).where({ target.targetName: "Bob" }).first().value();
How do I handle nested object with underscore/chain/where ? Thanks ! Any other ways are good too.
Use lodash libray https://lodash.com/
var environments=[
{
"name": "test",
"resourceLimits": {
"cpu": {
"min": 0.1, "max": 10
},
"target": {
"targetName": "del",
"env": "dev",
"region": "us-east-1"
}
}
}, {
"name": "test2",
"resourceLimits": {
"cpu": {
"min": 0.1,
"max": 10
},
"target": {
"targetName": "bob",
"env": "dev",
"region": "us-east-1"
}
}
}]
var res = _.find(environments, ['resourceLimits.target.targetName', 'bob']);
console.log(res.name);// "test2"
Try
let myEnv = _.chain(environments).where({ target.targetName: "Bob" }).first().value()