From b8148132ee5d2a37de1c01ac48e00427fde037b7 Mon Sep 17 00:00:00 2001 From: magodo Date: Tue, 31 Mar 2020 16:12:48 +0800 Subject: [PATCH 1/4] new resource: azurerm_log_analytics_datasource_windows_event --- .../services/loganalytics/registration.go | 1 + ..._log_analytics_datasource_windows_event.go | 216 +++++++++++++++++ ...analytics_datasource_windows_event_test.go | 220 ++++++++++++++++++ ...ics_datasource_windows_event.html.markdown | 83 +++++++ 4 files changed, 520 insertions(+) create mode 100644 azurerm/internal/services/loganalytics/resource_arm_log_analytics_datasource_windows_event.go create mode 100644 azurerm/internal/services/loganalytics/tests/resource_arm_log_analytics_datasource_windows_event_test.go create mode 100644 website/docs/r/log_analytics_datasource_windows_event.html.markdown diff --git a/azurerm/internal/services/loganalytics/registration.go b/azurerm/internal/services/loganalytics/registration.go index 0f8a5880ec77..a78709d556f6 100644 --- a/azurerm/internal/services/loganalytics/registration.go +++ b/azurerm/internal/services/loganalytics/registration.go @@ -30,6 +30,7 @@ func (r Registration) SupportedResources() map[string]*schema.Resource { "azurerm_log_analytics_linked_service": resourceArmLogAnalyticsLinkedService(), "azurerm_log_analytics_solution": resourceArmLogAnalyticsSolution(), "azurerm_log_analytics_workspace": resourceArmLogAnalyticsWorkspace(), + "azurerm_log_analytics_datasource_windows_event": resourceArmLogAnalyticsDataSourceWindowsEvent(), "azurerm_log_analytics_datasource_windows_performance_counter": resourceArmLogAnalyticsDataSourceWindowsPerformanceCounter(), } } diff --git a/azurerm/internal/services/loganalytics/resource_arm_log_analytics_datasource_windows_event.go b/azurerm/internal/services/loganalytics/resource_arm_log_analytics_datasource_windows_event.go new file mode 100644 index 000000000000..ab9eb65fe68f --- /dev/null +++ b/azurerm/internal/services/loganalytics/resource_arm_log_analytics_datasource_windows_event.go @@ -0,0 +1,216 @@ +package loganalytics + +import ( + "encoding/json" + "fmt" + "log" + "time" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/set" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/state" + + "github.com/Azure/azure-sdk-for-go/services/preview/operationalinsights/mgmt/2015-11-01-preview/operationalinsights" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/loganalytics/parse" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/structure" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/suppress" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceArmLogAnalyticsDataSourceWindowsEvent() *schema.Resource { + return &schema.Resource{ + Create: resourceArmLogAnalyticsDataSourceWindowsEventCreateUpdate, + Read: resourceArmLogAnalyticsDataSourceWindowsEventRead, + Update: resourceArmLogAnalyticsDataSourceWindowsEventCreateUpdate, + Delete: resourceArmLogAnalyticsDataSourceWindowsEventDelete, + + Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error { + _, err := parse.LogAnalyticsDataSourceID(id) + return err + }), + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Read: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "resource_group_name": azure.SchemaResourceGroupName(), + + "workspace_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: suppress.CaseDifference, + ValidateFunc: ValidateAzureRmLogAnalyticsWorkspaceName, + }, + + "event_log_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "event_types": { + Type: schema.TypeSet, + Required: true, + MinItems: 1, + Set: set.HashStringIgnoreCase, + Elem: &schema.Schema{ + Type: schema.TypeString, + // API backend accepts event_types case-insensitively + ValidateFunc: validation.StringInSlice([]string{"error", "warning", "information"}, true), + StateFunc: state.IgnoreCase, + DiffSuppressFunc: suppress.CaseDifference, + }, + }, + }, + } +} + +type dataSourceWindowsEvent struct { + EventLogName string `json:"eventLogName"` + EventTypes []dataSourceWindowsEventEventType `json:"eventTypes"` +} + +type dataSourceWindowsEventEventType struct { + EventType string `json:"eventType"` +} + +func resourceArmLogAnalyticsDataSourceWindowsEventCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).LogAnalytics.DataSourcesClient + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + name := d.Get("name").(string) + resourceGroup := d.Get("resource_group_name").(string) + workspaceName := d.Get("workspace_name").(string) + + if d.IsNewResource() { + resp, err := client.Get(ctx, resourceGroup, workspaceName, name) + if err != nil { + if !utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("failed to check for existing Log Analytics Data Source Windows Event %q (Resource Group %q / Workspace: %q): %+v", name, resourceGroup, workspaceName, err) + } + } + + if !utils.ResponseWasNotFound(resp.Response) { + return tf.ImportAsExistsError("azurerm_log_analytics_datasource_windows_event", *resp.ID) + } + } + + params := operationalinsights.DataSource{ + Kind: operationalinsights.WindowsEvent, + Properties: &dataSourceWindowsEvent{ + EventLogName: d.Get("event_log_name").(string), + EventTypes: expandLogAnalyticsDataSourceWindowsEventEventType(d.Get("event_types").(*schema.Set).List()), + }, + } + + if _, err := client.CreateOrUpdate(ctx, resourceGroup, workspaceName, name, params); err != nil { + return fmt.Errorf("failed to create Log Analytics DataSource Windows Event %q (Resource Group %q / Workspace: %q): %+v", name, resourceGroup, workspaceName, err) + } + + resp, err := client.Get(ctx, resourceGroup, workspaceName, name) + if err != nil { + return fmt.Errorf("Error retrieving Log Analytics Data Source Windows Event %q (Resource Group %q / Workspace: %q): %+v", name, resourceGroup, workspaceName, err) + } + if resp.ID == nil || *resp.ID == "" { + return fmt.Errorf("Cannot read Log Analytics Data Source Windows Event %q (Resource Group %q) ID", name, resourceGroup) + } + d.SetId(*resp.ID) + + return resourceArmLogAnalyticsDataSourceWindowsEventRead(d, meta) +} + +func resourceArmLogAnalyticsDataSourceWindowsEventRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).LogAnalytics.DataSourcesClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.LogAnalyticsDataSourceID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.Workspace, id.Name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[DEBUG] Log Analytics Data Source Windows Event %q was not found in Resource Group %q in Workspace %q - removing from state!", id.Name, id.ResourceGroup, id.Workspace) + d.SetId("") + return nil + } + + return fmt.Errorf("failed to retrieve Log Analytics Data Source Windows Event %q (Resource Group %q / Workspace: %q): %+v", id.Name, id.ResourceGroup, id.Workspace, err) + } + + d.Set("name", resp.Name) + d.Set("resource_group_name", id.ResourceGroup) + d.Set("workspace_name", id.Workspace) + if props := resp.Properties; props != nil { + propStr, err := structure.FlattenJsonToString(props.(map[string]interface{})) + if err != nil { + return fmt.Errorf("failed to flatten properties map to json for Log Analytics DataSource Windows Event %q (Resource Group %q / Workspace: %q): %+v", id.Name, id.ResourceGroup, id.Workspace, err) + } + + prop := dataSourceWindowsEvent{} + if err := json.Unmarshal([]byte(propStr), &prop); err != nil { + return fmt.Errorf("failed to decode properties json for Log Analytics DataSource Windows Event %q (Resource Group %q / Workspace: %q): %+v", id.Name, id.ResourceGroup, id.Workspace, err) + } + + d.Set("event_log_name", prop.EventLogName) + d.Set("event_types", flattenLogAnalyticsDataSourceWindowsEventEventType(prop.EventTypes)) + } + + return nil +} + +func resourceArmLogAnalyticsDataSourceWindowsEventDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).LogAnalytics.DataSourcesClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.LogAnalyticsDataSourceID(d.Id()) + if err != nil { + return err + } + + if _, err := client.Delete(ctx, id.ResourceGroup, id.Workspace, id.Name); err != nil { + return fmt.Errorf("failed to delete Log Analytics DataSource Windows Event %q (Resource Group %q / Workspace: %q): %+v", id.Name, id.ResourceGroup, id.Workspace, err) + } + + return nil +} + +func flattenLogAnalyticsDataSourceWindowsEventEventType(eventTypes []dataSourceWindowsEventEventType) []interface{} { + output := make([]interface{}, 0) + for _, e := range eventTypes { + output = append(output, e.EventType) + } + return output +} + +func expandLogAnalyticsDataSourceWindowsEventEventType(input []interface{}) []dataSourceWindowsEventEventType { + output := []dataSourceWindowsEventEventType{} + for _, eventType := range input { + output = append(output, dataSourceWindowsEventEventType{eventType.(string)}) + } + return output +} diff --git a/azurerm/internal/services/loganalytics/tests/resource_arm_log_analytics_datasource_windows_event_test.go b/azurerm/internal/services/loganalytics/tests/resource_arm_log_analytics_datasource_windows_event_test.go new file mode 100644 index 000000000000..7560cb163da4 --- /dev/null +++ b/azurerm/internal/services/loganalytics/tests/resource_arm_log_analytics_datasource_windows_event_test.go @@ -0,0 +1,220 @@ +package tests + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/loganalytics/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func TestAccAzureRMLogAnalyticsDataSourceWindowsEvent_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_log_analytics_datasource_windows_event", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMLogAnalyticsDataSourceWindowsEventDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMLogAnalyticsDataSourceWindowsEvent_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMLogAnalyticsDataSourceWindowsEventExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMLogAnalyticsDataSourceWindowsEvent_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_log_analytics_datasource_windows_event", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMLogAnalyticsDataSourceWindowsEventDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMLogAnalyticsDataSourceWindowsEvent_complete(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMLogAnalyticsDataSourceWindowsEventExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMLogAnalyticsDataSourceWindowsEvent_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_log_analytics_datasource_windows_event", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMLogAnalyticsDataSourceWindowsEventDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMLogAnalyticsDataSourceWindowsEvent_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMLogAnalyticsDataSourceWindowsEventExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMLogAnalyticsDataSourceWindowsEvent_complete(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMLogAnalyticsDataSourceWindowsEventExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMLogAnalyticsDataSourceWindowsEvent_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMLogAnalyticsDataSourceWindowsEventExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMLogAnalyticsDataSourceWindowsEvent_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_log_analytics_datasource_windows_event", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMLogAnalyticsDataSourceWindowsEventDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMLogAnalyticsDataSourceWindowsEvent_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMLogAnalyticsDataSourceWindowsEventExists(data.ResourceName), + ), + }, + data.RequiresImportErrorStep(testAccAzureRMLogAnalyticsDataSourceWindowsEvent_requiresImport), + }, + }) +} + +func testCheckAzureRMLogAnalyticsDataSourceWindowsEventExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + client := acceptance.AzureProvider.Meta().(*clients.Client).LogAnalytics.DataSourcesClient + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Log Analytics Data Source Windows Event not found: %s", resourceName) + } + + id, err := parse.LogAnalyticsDataSourceID(rs.Primary.ID) + if err != nil { + return err + } + + if resp, err := client.Get(ctx, id.ResourceGroup, id.Workspace, id.Name); err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Log Analytics Data Source Windows Event %q (Resource Group %q) does not exist", id.Name, id.ResourceGroup) + } + return fmt.Errorf("failed to get on LogAnalytics.DataSources: %+v", err) + } + + return nil + } +} + +func testCheckAzureRMLogAnalyticsDataSourceWindowsEventDestroy(s *terraform.State) error { + client := acceptance.AzureProvider.Meta().(*clients.Client).LogAnalytics.DataSourcesClient + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_log_analytics_datasource_windows_event" { + continue + } + + id, err := parse.LogAnalyticsDataSourceID(rs.Primary.ID) + if err != nil { + return err + } + + if resp, err := client.Get(ctx, id.ResourceGroup, id.Workspace, id.Name); err != nil { + if !utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("failed to get on LogAnalytics.DataSources: %+v", err) + } + } + + return nil + } + + return nil +} + +func testAccAzureRMLogAnalyticsDataSourceWindowsEvent_basic(data acceptance.TestData) string { + template := testAccAzureRMLogAnalyticsDataSourceWindowsEvent_template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_log_analytics_datasource_windows_event" "test" { + name = "acctestLADS-WE-%d" + resource_group_name = azurerm_resource_group.test.name + workspace_name = azurerm_log_analytics_workspace.test.name + event_log_name = "Application" + event_types = ["error"] +} +`, template, data.RandomInteger) +} + +func testAccAzureRMLogAnalyticsDataSourceWindowsEvent_complete(data acceptance.TestData) string { + template := testAccAzureRMLogAnalyticsDataSourceWindowsEvent_template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_log_analytics_datasource_windows_event" "test" { + name = "acctestLADS-WE-%d" + resource_group_name = azurerm_resource_group.test.name + workspace_name = azurerm_log_analytics_workspace.test.name + event_log_name = "Application" + event_types = ["InforMation", "warning", "Error"] +} +`, template, data.RandomInteger) +} + +func testAccAzureRMLogAnalyticsDataSourceWindowsEvent_requiresImport(data acceptance.TestData) string { + template := testAccAzureRMLogAnalyticsDataSourceWindowsEvent_basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_log_analytics_datasource_windows_event" "import" { + name = azurerm_log_analytics_datasource_windows_event.test.name + resource_group_name = azurerm_log_analytics_datasource_windows_event.test.resource_group_name + workspace_name = azurerm_log_analytics_datasource_windows_event.test.workspace_name + event_log_name = azurerm_log_analytics_datasource_windows_event.test.event_log_name + event_types = azurerm_log_analytics_datasource_windows_event.test.event_types +} +`, template) +} + +func testAccAzureRMLogAnalyticsDataSourceWindowsEvent_template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-la-%d" + 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" +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} diff --git a/website/docs/r/log_analytics_datasource_windows_event.html.markdown b/website/docs/r/log_analytics_datasource_windows_event.html.markdown new file mode 100644 index 000000000000..11e2ffd0387e --- /dev/null +++ b/website/docs/r/log_analytics_datasource_windows_event.html.markdown @@ -0,0 +1,83 @@ +--- +subcategory: "Log Analytics" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_log_analytics_datasource_windows_event" +description: |- + Manages a Log Analytics Windows Event DataSource. +--- + +# azurerm_log_analytics_datasource_windows_event + +Manages a Log Analytics Windows Event DataSource. + +## Example Usage + +```hcl +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "example" { + name = "example-resources" + location = "West Europe" +} + +resource "azurerm_log_analytics_workspace" "example" { + name = "example-law" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + sku = "PerGB2018" +} + +resource "azurerm_log_analytics_datasource_windows_performance_counter" "example" { + object_name = "CPU" + instance_name = "*" + counter_name = "CPU" + interval_seconds = 10 +} + +resource "azurerm_log_analytics_datasource_windows_event" "example" { + name = "example-lad-wpc" + resource_group_name = azurerm_resource_group.example.name + workspace_name = azurerm_log_analytics_workspace.example.name + event_log_name = "Application" + event_types = ["error"] +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `name` - (Required) The Name which should be used for this Log Analytics Windows Event DataSource. Changing this forces a new Log Analytics Windows Event DataSource to be created. + +* `resource_group_name` - (Required) The name of the Resource Group where the Log Analytics Windows Event DataSource should exist. Changing this forces a new Log Analytics Windows Event DataSource to be created. + +* `workspace_name` - (Required) TODO. Changing this forces a new Log Analytics Windows Event DataSource to be created. + +* `event_log_name` - (Required) Specifies the name of the Windows Event Log to collect events from. + +* `event_types` - (Required) Specifies an array of event types applied to the specified event log. Possible values include `error`, `warning` and `information`. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the Log Analytics Windows Event DataSource. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `create` - (Defaults to 30 minutes) Used when creating the Log Analytics Windows Event DataSource. +* `read` - (Defaults to 5 minutes) Used when retrieving the Log Analytics Windows Event DataSource. +* `update` - (Defaults to 30 minutes) Used when updating the Log Analytics Windows Event DataSource. +* `delete` - (Defaults to 30 minutes) Used when deleting the Log Analytics Windows Event DataSource. + +## Import + +Log Analytics Windows Event DataSources can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_log_analytics_datasource_windows_event.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.OperationalInsights/workspaces/workspace1/datasources/datasource1 +``` From ed87e8eac322858dd3004a1f4011c29f93fe8f5f Mon Sep 17 00:00:00 2001 From: magodo Date: Tue, 31 Mar 2020 17:02:05 +0800 Subject: [PATCH 2/4] miss out setting website index for resource --- website/azurerm.erb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/website/azurerm.erb b/website/azurerm.erb index 36191ed12138..8d5590f4e19a 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -1604,6 +1604,10 @@
  • Log Analytics Resources