Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for additional arguments on azurerm_api_management_api_diagnostic #9172

Merged
merged 9 commits into from
Nov 16, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/apimanagement/parse"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/apimanagement/validate"
azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/set"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)
Expand Down Expand Up @@ -59,6 +60,81 @@ func resourceArmApiManagementApiDiagnostic() *schema.Resource {
Required: true,
ValidateFunc: validate.ApiManagementLoggerID,
},

"sampling_percentage": {
Type: schema.TypeFloat,
Optional: true,
Computed: true,
ValidateFunc: validation.FloatBetween(0.0, 100.0),
},

"always_log_errors": {
Type: schema.TypeBool,
Optional: true,
Computed: true,
},

"verbosity": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.StringInSlice([]string{
string(apimanagement.Verbose),
string(apimanagement.Information),
string(apimanagement.Error),
}, false),
},

"log_client_ip": {
Type: schema.TypeBool,
Optional: true,
Computed: true,
},

"http_correlation_protocol": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.StringInSlice([]string{
string(apimanagement.HTTPCorrelationProtocolNone),
string(apimanagement.HTTPCorrelationProtocolLegacy),
string(apimanagement.HTTPCorrelationProtocolW3C),
}, false),
},

"frontend_request": resourceArmApiManagementApiDiagnosticAdditionalContentSchema(),

"frontend_response": resourceArmApiManagementApiDiagnosticAdditionalContentSchema(),

"backend_request": resourceArmApiManagementApiDiagnosticAdditionalContentSchema(),

"backend_response": resourceArmApiManagementApiDiagnosticAdditionalContentSchema(),
},
}
}

func resourceArmApiManagementApiDiagnosticAdditionalContentSchema() *schema.Schema {
return &schema.Schema{
Type: schema.TypeList,
MaxItems: 1,
Optional: true,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"body_bytes": {
Type: schema.TypeInt,
Optional: true,
ValidateFunc: validation.IntBetween(0, 8192),
},
"headers_to_log": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
Set: schema.HashString,
},
},
},
}
}
Expand Down Expand Up @@ -92,6 +168,61 @@ func resourceArmApiManagementApiDiagnosticCreateUpdate(d *schema.ResourceData, m
},
}

if samplingPercentage, ok := d.GetOk("sampling_percentage"); ok {
parameters.Sampling = &apimanagement.SamplingSettings{
SamplingType: apimanagement.Fixed,
Percentage: utils.Float(samplingPercentage.(float64)),
}
} else {
parameters.Sampling = nil
}

if alwaysLogErrors, ok := d.GetOk("always_log_errors"); ok && alwaysLogErrors.(bool) {
parameters.AlwaysLog = apimanagement.AllErrors
}

if verbosity, ok := d.GetOk("verbosity"); ok {
switch verbosity.(string) {
case string(apimanagement.Verbose):
parameters.Verbosity = apimanagement.Verbose
case string(apimanagement.Information):
parameters.Verbosity = apimanagement.Information
case string(apimanagement.Error):
parameters.Verbosity = apimanagement.Error
}
}

if logClientIP, ok := d.GetOk("log_client_ip"); ok {
parameters.LogClientIP = utils.Bool(logClientIP.(bool))
}

if httpCorrelationProtocol, ok := d.GetOk("http_correlation_protocol"); ok {
switch httpCorrelationProtocol.(string) {
case string(apimanagement.HTTPCorrelationProtocolNone):
parameters.HTTPCorrelationProtocol = apimanagement.HTTPCorrelationProtocolNone
case string(apimanagement.HTTPCorrelationProtocolLegacy):
parameters.HTTPCorrelationProtocol = apimanagement.HTTPCorrelationProtocolLegacy
case string(apimanagement.HTTPCorrelationProtocolW3C):
parameters.HTTPCorrelationProtocol = apimanagement.HTTPCorrelationProtocolW3C
}
}

if frontendRequest, ok := d.GetOk("frontend_request"); ok {
parameters.Frontend.Request = expandApiManagementApiDiagnosticHTTPMessageDiagnostic(frontendRequest.([]interface{}))
}

if frontendResponse, ok := d.GetOk("frontend_response"); ok {
parameters.Frontend.Response = expandApiManagementApiDiagnosticHTTPMessageDiagnostic(frontendResponse.([]interface{}))
}

if backendRequest, ok := d.GetOk("backend_request"); ok {
parameters.Backend.Request = expandApiManagementApiDiagnosticHTTPMessageDiagnostic(backendRequest.([]interface{}))
}

if backendResponse, ok := d.GetOk("backend_response"); ok {
parameters.Backend.Response = expandApiManagementApiDiagnosticHTTPMessageDiagnostic(backendResponse.([]interface{}))
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sirlatrom Getting a crash here, looks like parameters.Frontend / parameters.Backend are nil

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I'll look into it and ensure they are initialized correctly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be handled better now in 3dbe558.

if _, err := client.CreateOrUpdate(ctx, resourceGroup, serviceName, apiName, diagnosticId, parameters, ""); err != nil {
return fmt.Errorf("creating or updating Diagnostic %q (Resource Group %q / API Management Service %q / API %q): %+v", diagnosticId, resourceGroup, serviceName, apiName, err)
}
Expand Down Expand Up @@ -135,6 +266,27 @@ func resourceArmApiManagementApiDiagnosticRead(d *schema.ResourceData, meta inte
d.Set("api_management_name", diagnosticId.ServiceName)
if props := resp.DiagnosticContractProperties; props != nil {
d.Set("api_management_logger_id", props.LoggerID)
if props.Sampling != nil && props.Sampling.Percentage != nil {
d.Set("sampling_percentage", props.Sampling.Percentage)
}
d.Set("always_log_errors", props.AlwaysLog == apimanagement.AllErrors)
d.Set("verbosity", props.Verbosity)
d.Set("log_client_ip", props.LogClientIP)
d.Set("http_correlation_protocol", props.HTTPCorrelationProtocol)
if frontend := props.Frontend; frontend != nil {
d.Set("frontend_request", flattenApiManagementApiDiagnosticHTTPMessageDiagnostic(frontend.Request))
d.Set("frontend_response", flattenApiManagementApiDiagnosticHTTPMessageDiagnostic(frontend.Response))
} else {
d.Set("frontend_request", nil)
d.Set("frontend_response", nil)
}
if backend := props.Backend; backend != nil {
d.Set("backend_request", flattenApiManagementApiDiagnosticHTTPMessageDiagnostic(backend.Request))
d.Set("backend_response", flattenApiManagementApiDiagnosticHTTPMessageDiagnostic(backend.Response))
} else {
d.Set("backend_request", nil)
d.Set("backend_response", nil)
}
}

return nil
Expand All @@ -158,3 +310,48 @@ func resourceArmApiManagementApiDiagnosticDelete(d *schema.ResourceData, meta in

return nil
}

func expandApiManagementApiDiagnosticHTTPMessageDiagnostic(input []interface{}) *apimanagement.HTTPMessageDiagnostic {
if len(input) == 0 {
return nil
}

v := input[0].(map[string]interface{})

result := &apimanagement.HTTPMessageDiagnostic{
Body: &apimanagement.BodyDiagnosticSettings{
Bytes: utils.Int32(v["body_bytes"].(int32)),
},
}
sirlatrom marked this conversation as resolved.
Show resolved Hide resolved
if headersSetRaw, ok := v["headers_to_log"]; ok {
headersSet := headersSetRaw.(*schema.Set).List()
headers := []string{}
for _, header := range headersSet {
headers = append(headers, header.(string))
}
result.Headers = &headers
}

return result
}

func flattenApiManagementApiDiagnosticHTTPMessageDiagnostic(input *apimanagement.HTTPMessageDiagnostic) []interface{} {
result := make([]interface{}, 0)

if input == nil {
return result
}

diagnostic := map[string]interface{}{}

if input.Body != nil && input.Body.Bytes != nil {
diagnostic["body_bytes"] = input.Body.Bytes
}

if input.Headers != nil {
diagnostic["headers_to_log"] = set.FromStringSlice(*input.Headers)
}
result = append(result, diagnostic)

return result
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,25 @@ func TestAccAzureRMApiManagementApiDiagnostic_requiresImport(t *testing.T) {
})
}

func TestAccAzureRMApiManagementApiDiagnostic_complete(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_api_management_api_diagnostic", "test")

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acceptance.PreCheck(t) },
Providers: acceptance.SupportedProviders,
CheckDestroy: testCheckAzureRMApiManagementApiDiagnosticDestroy,
Steps: []resource.TestStep{
{
Config: testAccAzureRMApiManagementApiDiagnostic_complete(data),
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMApiManagementApiDiagnosticExists(data.ResourceName),
),
},
data.ImportStep(),
},
})
}

func testCheckAzureRMApiManagementApiDiagnosticDestroy(s *terraform.State) error {
client := acceptance.AzureProvider.Meta().(*clients.Client).ApiManagement.ApiDiagnosticClient
ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext
Expand Down Expand Up @@ -244,3 +263,43 @@ resource "azurerm_api_management_api_diagnostic" "import" {
}
`, template)
}

func testAccAzureRMApiManagementApiDiagnostic_complete(data acceptance.TestData) string {
config := testAccAzureRMApiManagementApiDiagnostic_template(data)
return fmt.Sprintf(`
%s

resource "azurerm_api_management_api_diagnostic" "test" {
identifier = "applicationinsights"
resource_group_name = azurerm_resource_group.test.name
api_management_name = azurerm_api_management.test.name
api_name = azurerm_api_management_api.test.name
api_management_logger_id = azurerm_api_management_logger.test.id
sampling_percentage = 10
always_log_errors = true
log_client_ip = true
http_correlation_protocol = "W3C"
verbosity = "verbose"

backend_request {
body_bytes = 1
headers_to_log = ["Host"]
}

backend_response {
body_bytes = 2
headers_to_log = ["Content-Type"]
}

frontend_request {
body_bytes = 3
headers_to_log = ["Accept"]
}

frontend_response {
body_bytes = 4
headers_to_log = ["Content-Length"]
}
}
`, config)
}
70 changes: 70 additions & 0 deletions website/docs/r/api_management_api_diagnostic.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,48 @@ resource "azurerm_api_management_api_diagnostic" "example" {
api_management_name = azurerm_api_management.example.name
api_name = azurerm_api_management_api.example.name
api_management_logger_id = azurerm_api_management_logger.example.id

sampling_percentage = 5.0
always_log_errors = true
log_client_ip = true
verbosity = "Verbose"
http_correlation_protocol = "W3C"

frontend_request {
body_bytes = 32
headers_to_log = [
"content-type",
"accept",
"origin",
]
}

frontend_response {
body_bytes = 32
headers_to_log = [
"content-type",
"content-length",
"origin",
]
}

backend_request {
body_bytes = 32
headers_to_log = [
"content-type",
"accept",
"origin",
]
}

backend_response {
body_bytes = 32
headers_to_log = [
"content-type",
"content-length",
"origin",
]
}
}
```

Expand All @@ -85,6 +127,34 @@ The following arguments are supported:

* `resource_group_name` - (Required) The name of the Resource Group where the API Management Service API Diagnostics Logs should exist. Changing this forces a new API Management Service API Diagnostics Logs to be created.

---

* `always_log_errors` - (Optional) Always log errors. Send telemetry if there is an erroneous condition, regardless of sampling settings.

* `backend_request` - (Optional) A `backend_request` block as defined below.

* `backend_response` - (Optional) A `backend_response` block as defined below.

* `frontend_request` - (Optional) A `frontend_request` block as defined below.

* `frontend_response` - (Optional) A `frontend_response` block as defined below.

* `http_correlation_protocol` - (Optional) The HTTP Correlation Protocol to use. Possible values are `None`, `Legacy` or `W3C`.

* `log_client_ip` - (Optional) Log client IP address.

* `sampling_percentage` - (Optional) Sampling (%). For high traffic APIs, please read this [documentation](https://docs.microsoft.com/azure/api-management/api-management-howto-app-insights#performance-implications-and-log-sampling) to understand performance implications and log sampling.
sirlatrom marked this conversation as resolved.
Show resolved Hide resolved

* `verbosity` - (Optional) Logging verbosity. Possible values are `verbose`, `information` or `error`.

---

A `backend_request`, `backend_response`, `frontend_request` or `frontend_response` block supports the following:

* `body_bytes` - (Optional) Number of payload bytes to log (up to 8192).

* `headers_to_log` - (Optional) Specifies a list of headers to log.

## Attributes Reference

In addition to the Arguments listed above - the following Attributes are exported:
Expand Down