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

Add Log Analytics support for ACI #2763

Merged
merged 9 commits into from
Mar 7, 2019
143 changes: 141 additions & 2 deletions azurerm/resource_arm_container_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,48 @@ func resourceArmContainerGroup() *schema.Resource {
},
},

"log_analytics": {
tombuildsstuff marked this conversation as resolved.
Show resolved Hide resolved
Type: schema.TypeSet,
metacpp marked this conversation as resolved.
Show resolved Hide resolved
Optional: true,
ForceNew: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"workspace_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validate.NoEmptyStrings,
metacpp marked this conversation as resolved.
Show resolved Hide resolved
},
"workspace_key": {
Type: schema.TypeString,
Required: true,
Sensitive: true,
ForceNew: true,
ValidateFunc: validate.NoEmptyStrings,
},
"log_type": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice([]string{
string(containerinstance.ContainerInsights),
string(containerinstance.ContainerInstanceLogs),
}, true),
metacpp marked this conversation as resolved.
Show resolved Hide resolved
},
"metadata": {
Type: schema.TypeMap,
Optional: true,
ForceNew: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
},
Set: containerGroupLogAnalyticsHash,
},

"ip_address": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -340,8 +382,17 @@ func resourceArmContainerGroupCreate(d *schema.ResourceData, meta interface{}) e
containerGroup.ContainerGroupProperties.IPAddress.DNSNameLabel = &dnsNameLabel
}

if _, err := client.CreateOrUpdate(ctx, resGroup, name, containerGroup); err != nil {
return err
containerGroup.Diagnostics = &containerinstance.ContainerGroupDiagnostics{
LogAnalytics: expandContainerLogAnalytics(d),
}

future, err := client.CreateOrUpdate(ctx, resGroup, name, containerGroup)
if err != nil {
return fmt.Errorf("Error creating/updating container group %q (Resource Group %q): %+v", name, resGroup, err)
}

if err = future.WaitForCompletionRef(ctx, client.Client); err != nil {
return fmt.Errorf("Error waiting for completion of container group %q (Resource Group %q): %+v", name, resGroup, err)
}

read, err := client.Get(ctx, resGroup, name)
Expand Down Expand Up @@ -406,7 +457,14 @@ func resourceArmContainerGroupRead(d *schema.ResourceData, meta interface{}) err

d.Set("restart_policy", string(props.RestartPolicy))
d.Set("os_type", string(props.OsType))

if diag := props.Diagnostics; diag != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

since we're combining this into a diagnostics block, we should move this within the flattenContainerLogAnalytics function (since that handles returning an empty list if this is nil) such that this is set regardless

if err := d.Set("log_analytics", flattenContainerLogAnalytics(diag.LogAnalytics)); err != nil {
return fmt.Errorf("Error setting `log_analytics`: %+v", err)
}
}
}

flattenAndSetTags(d, resp.Tags)

return nil
Expand Down Expand Up @@ -647,6 +705,33 @@ func expandContainerVolumes(input interface{}) (*[]containerinstance.VolumeMount
return &volumeMounts, &containerGroupVolumes
}

func expandContainerLogAnalytics(d *schema.ResourceData) *containerinstance.LogAnalytics {
logList := d.Get("log_analytics").(*schema.Set).List()

if len(logList) <= 0 {
return nil
}

log := logList[0].(map[string]interface{})
ws_id := log["workspace_id"].(string)
ws_key := log["workspace_key"].(string)
log_type := log["log_type"].(string)
metadataMap := log["metadata"].(map[string]interface{})
metadata := make(map[string]*string)
for k, v := range metadataMap {
// TODO:
metacpp marked this conversation as resolved.
Show resolved Hide resolved
strValue := v.(string)
metadata[k] = &strValue
}

return &containerinstance.LogAnalytics{
WorkspaceID: &ws_id,
WorkspaceKey: &ws_key,
LogType: containerinstance.LogAnalyticsLogType(log_type),
Metadata: metadata,
}
}

func flattenContainerImageRegistryCredentials(d *schema.ResourceData, input *[]containerinstance.ImageRegistryCredential) []interface{} {
if input == nil {
return nil
Expand Down Expand Up @@ -876,6 +961,37 @@ func flattenContainerVolumes(volumeMounts *[]containerinstance.VolumeMount, cont
return volumeConfigs
}

func flattenContainerLogAnalytics(input *containerinstance.LogAnalytics) *schema.Set {
if input == nil {
return nil
}

log := make(map[string]interface{})
logSet := schema.Set{
F: containerGroupLogAnalyticsHash,
}
if input.WorkspaceID != nil {
log["workspace_id"] = *input.WorkspaceID
}

if input.WorkspaceKey != nil {
log["workspace_key"] = *input.WorkspaceKey
}

log["log_type"] = input.LogType
tombuildsstuff marked this conversation as resolved.
Show resolved Hide resolved

// TODO: string ?
metadata := make(map[string]interface{})
for k, v := range input.Metadata {
metadata[k] = *v
}
log["metadata"] = metadata

logSet.Add(log)

return &logSet
}

func resourceArmContainerGroupPortsHash(v interface{}) int {
var buf bytes.Buffer

Expand All @@ -886,3 +1002,26 @@ func resourceArmContainerGroupPortsHash(v interface{}) int {

return hashcode.String(buf.String())
}

func containerGroupLogAnalyticsHash(v interface{}) int {
var buf bytes.Buffer

if m, ok := v.(map[string]interface{}); ok {
buf.WriteString(fmt.Sprintf("%s-", m["workspace_id"].(string)))

if v, ok := m["log_type"].(containerinstance.LogAnalyticsLogType); ok {
buf.WriteString(fmt.Sprintf("%s-", string(v)))
}
if v, ok := m["log_type"].(string); ok {
buf.WriteString(fmt.Sprintf("%s-", v))
}

metadata := m["metadata"].(map[string]interface{})
for k, v := range metadata {
buf.WriteString(fmt.Sprintf("%s-", k))
buf.WriteString(fmt.Sprintf("%s-", v.(string)))
}
}

return hashcode.String(buf.String())
}
64 changes: 62 additions & 2 deletions azurerm/resource_arm_container_group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ func TestAccAzureRMContainerGroup_linuxComplete(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "container.0.volume.0.read_only", "false"),
resource.TestCheckResourceAttr(resourceName, "os_type", "Linux"),
resource.TestCheckResourceAttr(resourceName, "restart_policy", "OnFailure"),
resource.TestCheckResourceAttr(resourceName, "log_analytics.#", "1"),
),
metacpp marked this conversation as resolved.
Show resolved Hide resolved
},
{
Expand Down Expand Up @@ -293,6 +294,7 @@ func TestAccAzureRMContainerGroup_windowsComplete(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "container.0.secure_environment_variables.secureFoo1", "secureBar1"),
resource.TestCheckResourceAttr(resourceName, "os_type", "Windows"),
resource.TestCheckResourceAttr(resourceName, "restart_policy", "Never"),
resource.TestCheckResourceAttr(resourceName, "log_analytics.#", "1"),
metacpp marked this conversation as resolved.
Show resolved Hide resolved
),
},
{
Expand Down Expand Up @@ -543,6 +545,26 @@ resource "azurerm_resource_group" "test" {
location = "%s"
}

resource "azurerm_log_analytics_workspace" "test" {
name = "acctestLAW-%d"
location = "${azurerm_resource_group.test.location}"
resource_group_name = "${azurerm_resource_group.test.name}"
sku = "PerGB2018"
}

resource "azurerm_log_analytics_solution" "test" {
solution_name = "ContainerInsights"
location = "${azurerm_resource_group.test.location}"
resource_group_name = "${azurerm_resource_group.test.name}"
workspace_resource_id = "${azurerm_log_analytics_workspace.test.id}"
workspace_name = "${azurerm_log_analytics_workspace.test.name}"

plan {
publisher = "Microsoft"
product = "OMSGallery/ContainerInsights"
}
}

resource "azurerm_container_group" "test" {
name = "acctestcontainergroup-%d"
location = "${azurerm_resource_group.test.location}"
Expand Down Expand Up @@ -575,11 +597,20 @@ resource "azurerm_container_group" "test" {
commands = ["cmd.exe", "echo", "hi"]
}

log_analytics {
workspace_id = "${azurerm_log_analytics_workspace.test.workspace_id}"
workspace_key = "${azurerm_log_analytics_workspace.test.primary_shared_key}"
log_type = "ContainerInsights"
metadata {
"node-name" = "acctestContainerGroup"
}
}

tags {
environment = "Testing"
}
}
`, ri, location, ri, ri)
`, ri, location, ri, ri, ri)
}

func testAccAzureRMContainerGroup_linuxComplete(ri int, location string) string {
Expand All @@ -589,6 +620,26 @@ resource "azurerm_resource_group" "test" {
location = "%s"
}

resource "azurerm_log_analytics_workspace" "test" {
name = "acctestLAW-%d"
location = "${azurerm_resource_group.test.location}"
resource_group_name = "${azurerm_resource_group.test.name}"
sku = "PerGB2018"
}

resource "azurerm_log_analytics_solution" "test" {
solution_name = "ContainerInsights"
location = "${azurerm_resource_group.test.location}"
resource_group_name = "${azurerm_resource_group.test.name}"
workspace_resource_id = "${azurerm_log_analytics_workspace.test.id}"
workspace_name = "${azurerm_log_analytics_workspace.test.name}"

plan {
publisher = "Microsoft"
product = "OMSGallery/ContainerInsights"
}
}

resource "azurerm_storage_account" "test" {
name = "accsa%d"
resource_group_name = "${azurerm_resource_group.test.name}"
Expand Down Expand Up @@ -649,11 +700,20 @@ resource "azurerm_container_group" "test" {
commands = ["/bin/bash", "-c", "ls"]
}

log_analytics {
workspace_id = "${azurerm_log_analytics_workspace.test.workspace_id}"
workspace_key = "${azurerm_log_analytics_workspace.test.primary_shared_key}"
log_type = "ContainerInsights"
metadata {
"node-name" = "acctestContainerGroup"
}
}

tags {
environment = "Testing"
}
}
`, ri, location, ri, ri, ri, ri)
`, ri, location, ri, ri, ri, ri, ri)
}

func testCheckAzureRMContainerGroupExists(resourceName string) resource.TestCheckFunc {
Expand Down
26 changes: 25 additions & 1 deletion website/docs/r/container_group.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,18 @@ The following arguments are supported:

* `restart_policy` - (Optional) Restart policy for the container group. Allowed values are `Always`, `Never`, `OnFailure`. Defaults to `Always`.
tombuildsstuff marked this conversation as resolved.
Show resolved Hide resolved

* `image_registry_credential` - (Optional) Set image registry credentials for the group as documented in the `image_registry_credential` block below
* `image_registry_credential` - (Optional) Set image registry credentials for the group as documented in the `image_registry_credential` block below.

* `container` - (Required) The definition of a container that is part of the group as documented in the `container` block below. Changing this forces a new resource to be created.

* `log_analytics` - (Optional) The information of Log Analytics for the group as documented in the `log_analytics` block below. Changing this forces a new resource to be created.
tombuildsstuff marked this conversation as resolved.
Show resolved Hide resolved

~> **Note:** if `os_type` is set to `Windows` currently only a single `container` block is supported.

* `tags` - (Optional) A mapping of tags to assign to the resource.

---

The `container` block supports:

* `name` - (Required) Specifies the name of the Container. Changing this forces a new resource to be created.
Expand All @@ -142,6 +146,8 @@ The `container` block supports:

* `volume` - (Optional) The definition of a volume mount for this container as documented in the `volume` block below. Changing this forces a new resource to be created.

---

The `volume` block supports:

* `name` - (Required) The name of the volume mount. Changing this forces a new resource to be created.
Expand All @@ -156,6 +162,8 @@ The `volume` block supports:

* `share_name` - (Required) The Azure storage share that is to be mounted as a volume. This must be created on the storage account specified as above. Changing this forces a new resource to be created.

---

The `image_registry_credential` block supports:

* `username` - (Required) The username with which to connect to the registry.
Expand All @@ -164,12 +172,28 @@ The `image_registry_credential` block supports:

* `server` - (Required) The address to use to connect to the registry without protocol ("https"/"http"). For example: "myacr.acr.io"

---

The `ports` block supports:

* `port` - (Required) The port number the container will expose.

* `protocol` - (Required) The network protocol associated with port. Possible values are `TCP` & `UDP`.

---

The `log_analytics` block supports:
tombuildsstuff marked this conversation as resolved.
Show resolved Hide resolved

* `workspace_id` - (Required) The workspace id for Log Analytics.

~> **NOTE:** This field is `workspace_id` of `azurerm_log_analytics_workspace.test.workspace_id`, NOT `id`.

* `workspace_key` - (Required) The workspace key for Log Analytics.

* `log_type` - (Required) The log type to be used. Possible values include: `ContainerInsights` and `ContainerInstanceLogs`.

* `metadata` - (Optional) The metadata for Log Analytics.

## Attributes Reference

The following attributes are exported:
Expand Down