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

Adding Operational Insight Workspace (a.k.a Log Analytics) #331

Merged
merged 28 commits into from
Sep 26, 2017
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
78cca50
Adding operationalinsight workspace
TsuyoshiUshio Sep 13, 2017
db9621c
Set SKU as default
TsuyoshiUshio Sep 13, 2017
357bc06
Follow the naming Rule with using location Sceme
TsuyoshiUshio Sep 22, 2017
ae309e0
Merge branch 'master' into functions-provider
TsuyoshiUshio Sep 22, 2017
d5ebef8
Use resourceGroupNameSchema()
TsuyoshiUshio Sep 23, 2017
75dc27c
Remove comment. I'll write the comment to the documentation.
TsuyoshiUshio Sep 23, 2017
1fe74ea
Adding SKU types validation
TsuyoshiUshio Sep 23, 2017
e86a8a2
Refactor: Remove getSku(). We don't need to write this, we can use Sk…
TsuyoshiUshio Sep 23, 2017
c3408b2
Follow the coding style.
TsuyoshiUshio Sep 23, 2017
2f74b8e
Remove unnecessary comment
TsuyoshiUshio Sep 23, 2017
4d4678f
Error message improvement to dump more for error struct.
TsuyoshiUshio Sep 23, 2017
011e38f
Make error more dump for error struct
TsuyoshiUshio Sep 23, 2017
c821a98
Using utility method.
TsuyoshiUshio Sep 23, 2017
577502d
Adding workspace name validation
TsuyoshiUshio Sep 23, 2017
3e8c7b5
Follow the naming rule
TsuyoshiUshio Sep 23, 2017
a578ba2
Adjust SDK version for operational insight
TsuyoshiUshio Sep 23, 2017
0cd140a
Change provider name and fix the Acceptance testing error
TsuyoshiUshio Sep 24, 2017
ea0692e
Adding the log anaylytics documentation
TsuyoshiUshio Sep 24, 2017
87b6e9a
Fix Travis-CI issue. It prevent make vet works.
TsuyoshiUshio Sep 24, 2017
9b64611
Edit the message for fit the error root cause
TsuyoshiUshio Sep 24, 2017
7c6ffaa
Changing name into OperationalInsight to LogAnalytics
TsuyoshiUshio Sep 25, 2017
a260e4f
Change the validation function to validation library
TsuyoshiUshio Sep 25, 2017
204c2fb
Fix in case of SKU is null
TsuyoshiUshio Sep 25, 2017
68bec07
Fix tyop and Fix the Operational Insight in Log messages
TsuyoshiUshio Sep 25, 2017
01fa92d
Fix Documentation hightlight.
TsuyoshiUshio Sep 25, 2017
5ced761
Comparing the Resource Group name in a case-insensitive manor
tombuildsstuff Sep 26, 2017
8e33ee6
Minor documentation cleanup
tombuildsstuff Sep 26, 2017
57b177f
`azurerm_log_analytics` -> `azurerm_log_analytics_workspace`
tombuildsstuff Sep 26, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions azurerm/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/Azure/azure-sdk-for-go/arm/graphrbac"
"github.com/Azure/azure-sdk-for-go/arm/keyvault"
"github.com/Azure/azure-sdk-for-go/arm/network"
"github.com/Azure/azure-sdk-for-go/arm/operationalinsights"
"github.com/Azure/azure-sdk-for-go/arm/postgresql"
"github.com/Azure/azure-sdk-for-go/arm/redis"
"github.com/Azure/azure-sdk-for-go/arm/resources/resources"
Expand Down Expand Up @@ -98,6 +99,8 @@ type ArmClient struct {
eventHubConsumerGroupClient eventhub.ConsumerGroupsClient
eventHubNamespacesClient eventhub.NamespacesClient

workspacesClient operationalinsights.WorkspacesClient

postgresqlConfigurationsClient postgresql.ConfigurationsClient
postgresqlDatabasesClient postgresql.DatabasesClient
postgresqlFirewallRulesClient postgresql.FirewallRulesClient
Expand Down Expand Up @@ -400,6 +403,12 @@ func (c *Config) getArmClient() (*ArmClient, error) {
lgc.Sender = sender
client.localNetConnClient = lgc

opwc := operationalinsights.NewWorkspacesClient(c.SubscriptionID)
setUserAgent(&opwc.Client)
opwc.Authorizer = auth
opwc.Sender = autorest.CreateSender(withRequestLogging())
client.workspacesClient = opwc

pipc := network.NewPublicIPAddressesClientWithBaseURI(endpoint, c.SubscriptionID)
setUserAgent(&pipc.Client)
pipc.Authorizer = auth
Expand Down
56 changes: 56 additions & 0 deletions azurerm/import_arm_log_analytics_workspace_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package azurerm

import (
"testing"

"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
)

func TestAccAzureRMLogAnalyticsWorkspace_importRequiredOnly(t *testing.T) {
resourceName := "azurerm_log_analytics.test"

ri := acctest.RandInt()
config := testAccAzureRMLogAnalyticsWorkspace_requiredOnly(ri, testLocation())

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testCheckAzureRMLogAnalyticsWorkspaceDestroy,
Steps: []resource.TestStep{
{
Config: config,
},

{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccAzureRMLogAnalyticsWorkspace_importRetentionInDaysComplete(t *testing.T) {
resourceName := "azurerm_log_analytics.test"

ri := acctest.RandInt()
config := testAccAzureRMLogAnalyticsWorkspace_retentionInDaysComplete(ri, testLocation())

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testCheckAzureRMLogAnalyticsWorkspaceDestroy,
Steps: []resource.TestStep{
{
Config: config,
},

{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}
41 changes: 22 additions & 19 deletions azurerm/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ func Provider() terraform.ResourceProvider {
"azurerm_lb_probe": resourceArmLoadBalancerProbe(),
"azurerm_lb_rule": resourceArmLoadBalancerRule(),
"azurerm_local_network_gateway": resourceArmLocalNetworkGateway(),
"azurerm_log_analytics": resourceArmLogAnalyticsWorkspaceService(),
"azurerm_managed_disk": resourceArmManagedDisk(),
"azurerm_network_interface": resourceArmNetworkInterface(),
"azurerm_network_security_group": resourceArmNetworkSecurityGroup(),
Expand Down Expand Up @@ -381,25 +382,26 @@ var providerRegistrationOnce sync.Once

func determineAzureResourceProvidersToRegister(providerList []resources.Provider) map[string]struct{} {
providers := map[string]struct{}{
"Microsoft.Automation": {},
"Microsoft.Cache": {},
"Microsoft.Cdn": {},
"Microsoft.Compute": {},
"Microsoft.ContainerInstance": {},
"Microsoft.ContainerRegistry": {},
"Microsoft.ContainerService": {},
"Microsoft.DBforPostgreSQL": {},
"Microsoft.DocumentDB": {},
"Microsoft.EventGrid": {},
"Microsoft.EventHub": {},
"Microsoft.KeyVault": {},
"microsoft.insights": {},
"Microsoft.Network": {},
"Microsoft.Resources": {},
"Microsoft.Search": {},
"Microsoft.ServiceBus": {},
"Microsoft.Sql": {},
"Microsoft.Storage": {},
"Microsoft.Automation": {},
"Microsoft.Cache": {},
"Microsoft.Cdn": {},
"Microsoft.Compute": {},
"Microsoft.ContainerInstance": {},
"Microsoft.ContainerRegistry": {},
"Microsoft.ContainerService": {},
"Microsoft.DBforPostgreSQL": {},
"Microsoft.DocumentDB": {},
"Microsoft.EventGrid": {},
"Microsoft.EventHub": {},
"Microsoft.KeyVault": {},
"microsoft.insights": {},
"Microsoft.Network": {},
"Microsoft.OperationalInsights": {},
"Microsoft.Resources": {},
"Microsoft.Search": {},
"Microsoft.ServiceBus": {},
"Microsoft.Sql": {},
"Microsoft.Storage": {},
}

// filter out any providers already registered
Expand All @@ -424,6 +426,7 @@ func determineAzureResourceProvidersToRegister(providerList []resources.Provider
func registerAzureResourceProvidersWithSubscription(providerList []resources.Provider, client resources.ProvidersClient) error {
var err error
providerRegistrationOnce.Do(func() {

providers := determineAzureResourceProvidersToRegister(providerList)

var wg sync.WaitGroup
Expand Down
201 changes: 201 additions & 0 deletions azurerm/resource_arm_log_analytics_workspace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
package azurerm

import (
"fmt"
"log"
"regexp"

"github.com/Azure/azure-sdk-for-go/arm/operationalinsights"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"

"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

func resourceArmLogAnalyticsWorkspaceService() *schema.Resource {
return &schema.Resource{
Create: resourceArmLogAnalyticsWorkspaceCreateUpdate,
Read: resourceArmLogAnalyticsWorkspaceRead,
Update: resourceArmLogAnalyticsWorkspaceCreateUpdate,
Delete: resourceArmLogAnalyticsWorkspaceDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validateAzureRmLogAnalyticsWorkspaceName,
},
"location": locationSchema(),
"resource_group_name": resourceGroupNameSchema(),
"workspace_id": {
Type: schema.TypeString,
Computed: true,
},
"portal_url": {
Type: schema.TypeString,
Computed: true,
},
"sku": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice([]string{
string(operationalinsights.Free),
string(operationalinsights.PerNode),
string(operationalinsights.Premium),
string(operationalinsights.Standalone),
string(operationalinsights.Standard),
string(operationalinsights.Unlimited),
}, true),
DiffSuppressFunc: ignoreCaseDiffSuppressFunc,
},
"retention_in_days": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
ValidateFunc: validation.IntBetween(30, 730),
},
"primary_shared_key": {
Type: schema.TypeString,
Computed: true,
},
"secondary_shared_key": {
Type: schema.TypeString,
Computed: true,
},
"tags": tagsSchema(),
},
}
}

func resourceArmLogAnalyticsWorkspaceCreateUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).workspacesClient
log.Printf("[INFO] preparing arguments for AzureRM Log Analytics workspace creation.")

name := d.Get("name").(string)
location := d.Get("location").(string)
resGroup := d.Get("resource_group_name").(string)

skuName := d.Get("sku").(string)
sku := &operationalinsights.Sku{
Name: operationalinsights.SkuNameEnum(skuName),
}

retentionInDays := int32(d.Get("retention_in_days").(int))

tags := d.Get("tags").(map[string]interface{})

parameters := operationalinsights.Workspace{
Name: &name,
Location: &location,
Tags: expandTags(tags),
WorkspaceProperties: &operationalinsights.WorkspaceProperties{
Sku: sku,
RetentionInDays: &retentionInDays,
},
}

_, error := client.CreateOrUpdate(resGroup, name, parameters, make(chan struct{}))
err := <-error
if err != nil {
return err
}

read, err := client.Get(resGroup, name)
if err != nil {
return err
}

if read.ID == nil {
return fmt.Errorf("Cannot read Log Analytics Workspace '%s' (resource group %s) ID", name, resGroup)
}

d.SetId(*read.ID)

return resourceArmLogAnalyticsWorkspaceRead(d, meta)

}

func resourceArmLogAnalyticsWorkspaceRead(d *schema.ResourceData, meta interface{}) error {

client := meta.(*ArmClient).workspacesClient
id, err := parseAzureResourceID(d.Id())
if err != nil {
return err
}
resGroup := id.ResourceGroup
name := id.Path["workspaces"]

resp, err := client.Get(resGroup, name)
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
d.SetId("")
return nil
}
return fmt.Errorf("Error making Read request on AzureRM Log Analytics workspaces '%s': %+v", name, err)
}

d.Set("name", resp.Name)
d.Set("location", resp.Location)
d.Set("resource_group_name", resGroup)
d.Set("workspace_id", resp.CustomerID)
d.Set("portal_url", resp.PortalURL)
if sku := resp.Sku; sku != nil {
d.Set("sku", resp.Sku.Name)
Copy link
Contributor

Choose a reason for hiding this comment

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

this can actually become just sku.Name rather resp.Sku.Name - since we're assigning the variable to null check it :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good Point! I fix it. :)

}
d.Set("retention_in_days", resp.RetentionInDays)

sharedKeys, err := client.GetSharedKeys(resGroup, name)
if err != nil {
log.Printf("[ERROR] Unable to List Shared keys for Log Analytics workspaces %s: %+v", name, err)
} else {
d.Set("primary_shared_key", sharedKeys.PrimarySharedKey)
d.Set("secondary_shared_key", sharedKeys.SecondarySharedKey)
}

flattenAndSetTags(d, resp.Tags)
return nil
}

func resourceArmLogAnalyticsWorkspaceDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).workspacesClient

id, err := parseAzureResourceID(d.Id())
if err != nil {
return err
}
resGroup := id.ResourceGroup
name := id.Path["workspaces"]

resp, err := client.Delete(resGroup, name)

if err != nil {
if utils.ResponseWasNotFound(resp) {
return nil
}

return fmt.Errorf("Error issuing AzureRM delete request for Log Analytics Workspaces '%s': %+v", name, err)
}

return nil
}

func validateAzureRmLogAnalyticsWorkspaceName(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)

r, _ := regexp.Compile("^[A-Za-z0-9][A-Za-z0-9-]+[A-Za-z0-9]$")
if !r.MatchString(value) {
errors = append(errors, fmt.Errorf("Workspace Name can only contain alphabet, number, and '-' character. You can not use '-' as the start and end of the name"))
}

length := len(value)
if length > 63 || 4 > length {
errors = append(errors, fmt.Errorf("Workspace Name can only be between 4 and 63 letters"))
}

return
}
Loading