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
116 changes: 114 additions & 2 deletions azurerm/resource_arm_container_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ import (
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

const (
LogAnalyticsWorkSpaceKeyPath = "log_analytics.0.workspace_key"
tombuildsstuff marked this conversation as resolved.
Show resolved Hide resolved
)

func resourceArmContainerGroup() *schema.Resource {
return &schema.Resource{
Create: resourceArmContainerGroupCreate,
Expand Down Expand Up @@ -279,6 +283,47 @@ func resourceArmContainerGroup() *schema.Resource {
},
},

"log_analytics": {
tombuildsstuff marked this conversation as resolved.
Show resolved Hide resolved
Type: schema.TypeList,
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.UUID,
},
"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),
}, false),
},
"metadata": {
Type: schema.TypeMap,
Optional: true,
ForceNew: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
},
},

"ip_address": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -340,8 +385,18 @@ 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
logList := d.Get("log_analytics").([]interface{})
containerGroup.Diagnostics = &containerinstance.ContainerGroupDiagnostics{
LogAnalytics: expandContainerLogAnalytics(logList),
tombuildsstuff marked this conversation as resolved.
Show resolved Hide resolved
}

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 +461,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(d, 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 +709,30 @@ func expandContainerVolumes(input interface{}) (*[]containerinstance.VolumeMount
return &volumeMounts, &containerGroupVolumes
}

func expandContainerLogAnalytics(logList []interface{}) *containerinstance.LogAnalytics {
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 {
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 +962,32 @@ func flattenContainerVolumes(volumeMounts *[]containerinstance.VolumeMount, cont
return volumeConfigs
}

func flattenContainerLogAnalytics(d *schema.ResourceData, input *containerinstance.LogAnalytics) []interface{} {
if input == nil {
return []interface{}{}
}

log := make(map[string]interface{})

if input.WorkspaceID != nil {
log["workspace_id"] = *input.WorkspaceID
}

if v, ok := d.GetOk(LogAnalyticsWorkSpaceKeyPath); ok {
tombuildsstuff marked this conversation as resolved.
Show resolved Hide resolved
log["workspace_key"] = v
}

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

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

return []interface{}{log}
}

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

Expand Down
75 changes: 73 additions & 2 deletions azurerm/resource_arm_container_group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"net/http"
"testing"

"github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2018-10-01/containerinstance"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf"
Expand Down Expand Up @@ -217,6 +218,11 @@ 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"),
resource.TestCheckResourceAttr(resourceName, "log_analytics.0.log_type", string(containerinstance.ContainerInsights)),
tombuildsstuff marked this conversation as resolved.
Show resolved Hide resolved
resource.TestCheckResourceAttr(resourceName, "log_analytics.0.metadata.%", "1"),
resource.TestCheckResourceAttrSet(resourceName, "log_analytics.0.workspace_id"),
resource.TestCheckResourceAttrSet(resourceName, "log_analytics.0.workspace_key"),
),
metacpp marked this conversation as resolved.
Show resolved Hide resolved
},
{
Expand All @@ -228,6 +234,7 @@ func TestAccAzureRMContainerGroup_linuxComplete(t *testing.T) {
"container.0.secure_environment_variables.%",
"container.0.secure_environment_variables.secureFoo",
"container.0.secure_environment_variables.secureFoo1",
"log_analytics.0.workspace_key",
},
},
},
Expand Down Expand Up @@ -293,6 +300,11 @@ 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
resource.TestCheckResourceAttr(resourceName, "log_analytics.0.log_type", string(containerinstance.ContainerInsights)),
resource.TestCheckResourceAttr(resourceName, "log_analytics.0.metadata.%", "1"),
resource.TestCheckResourceAttrSet(resourceName, "log_analytics.0.workspace_id"),
resource.TestCheckResourceAttrSet(resourceName, "log_analytics.0.workspace_key"),
),
},
{
Expand All @@ -303,6 +315,7 @@ func TestAccAzureRMContainerGroup_windowsComplete(t *testing.T) {
"container.0.secure_environment_variables.%",
"container.0.secure_environment_variables.secureFoo",
"container.0.secure_environment_variables.secureFoo1",
"log_analytics.0.workspace_key",
},
},
},
Expand Down Expand Up @@ -543,6 +556,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 +608,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 +631,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 +711,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