Skip to content

Commit

Permalink
Merge pull request #952 from lawrencegripper/loganalytics_solution
Browse files Browse the repository at this point in the history
New Resource: `azurerm_log_analytics_solution`
  • Loading branch information
tombuildsstuff committed Mar 12, 2018
2 parents 7278dd6 + fcd5b64 commit 265f47e
Show file tree
Hide file tree
Showing 18 changed files with 2,035 additions and 1 deletion.
6 changes: 6 additions & 0 deletions azurerm/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/Azure/azure-sdk-for-go/services/mysql/mgmt/2017-04-30-preview/mysql"
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2017-09-01/network"
"github.com/Azure/azure-sdk-for-go/services/operationalinsights/mgmt/2015-11-01-preview/operationalinsights"
"github.com/Azure/azure-sdk-for-go/services/operationsmanagement/mgmt/2015-11-01-preview/operationsmanagement"
"github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2017-04-30-preview/postgresql"
"github.com/Azure/azure-sdk-for-go/services/redis/mgmt/2016-04-01/redis"
"github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-06-01/subscriptions"
Expand Down Expand Up @@ -82,6 +83,7 @@ type ArmClient struct {
eventHubNamespacesClient eventhub.NamespacesClient

workspacesClient operationalinsights.WorkspacesClient
solutionsClient operationsmanagement.SolutionsClient

redisClient redis.Client
redisFirewallClient redis.FirewallRuleClient
Expand Down Expand Up @@ -736,6 +738,10 @@ func (c *ArmClient) registerOperationalInsightsClients(endpoint, subscriptionId
opwc := operationalinsights.NewWorkspacesClient(subscriptionId)
c.configureClient(&opwc.Client, auth)
c.workspacesClient = opwc

solutionsClient := operationsmanagement.NewSolutionsClient(subscriptionId, "Microsoft.OperationsManagement", "solutions", "testing")
c.configureClient(&solutionsClient.Client, auth)
c.solutionsClient = solutionsClient
}

func (c *ArmClient) registerRedisClients(endpoint, subscriptionId string, auth autorest.Authorizer, sender autorest.Sender) {
Expand Down
32 changes: 32 additions & 0 deletions azurerm/import_arm_log_analytics_solution_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package azurerm

import (
"testing"

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

func TestAccAzureRMLogAnalyticsSolution_containerMonitoring(t *testing.T) {
resourceName := "azurerm_log_analytics_solution.test"

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

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

{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}
1 change: 1 addition & 0 deletions azurerm/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ func Provider() terraform.ResourceProvider {
"azurerm_lb_probe": resourceArmLoadBalancerProbe(),
"azurerm_lb_rule": resourceArmLoadBalancerRule(),
"azurerm_local_network_gateway": resourceArmLocalNetworkGateway(),
"azurerm_log_analytics_solution": resourceArmLogAnalyticsSolution(),
"azurerm_log_analytics_workspace": resourceArmLogAnalyticsWorkspace(),
"azurerm_managed_disk": resourceArmManagedDisk(),
"azurerm_management_lock": resourceArmManagementLock(),
Expand Down
225 changes: 225 additions & 0 deletions azurerm/resource_arm_log_analytics_solution.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
package azurerm

import (
"fmt"
"log"
"strings"

"github.com/Azure/azure-sdk-for-go/services/operationsmanagement/mgmt/2015-11-01-preview/operationsmanagement"

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

func resourceArmLogAnalyticsSolution() *schema.Resource {
return &schema.Resource{
Create: resourceArmLogAnalyticsSolutionCreateUpdate,
Read: resourceArmLogAnalyticsSolutionRead,
Update: resourceArmLogAnalyticsSolutionCreateUpdate,
Delete: resourceArmLogAnalyticsSolutionDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"solution_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},

"location": locationSchema(),

"resource_group_name": resourceGroupNameDiffSuppressSchema(),

"plan": {
Type: schema.TypeList,
Required: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Computed: true,
},
"publisher": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"promotion_code": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"product": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
},
},
},

"workspace_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},

"workspace_resource_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
DiffSuppressFunc: ignoreCaseDiffSuppressFunc,
},
},
}
}

func resourceArmLogAnalyticsSolutionCreateUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).solutionsClient
ctx := meta.(*ArmClient).StopContext
log.Printf("[INFO] preparing arguments for AzureRM Log Analytics solution creation.")

// The resource requires both .name and .plan.name are set in the format
// "SolutionName(WorkspaceName)". Feedback will be submitted to the OMS team as IMO this isn't ideal.
name := fmt.Sprintf("%s(%s)", d.Get("solution_name").(string), d.Get("workspace_name").(string))
solutionPlan := expandAzureRmLogAnalyticsSolutionPlan(d)
solutionPlan.Name = &name

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

parameters := operationsmanagement.Solution{
Name: &name,
Location: &location,
Plan: &solutionPlan,
Properties: &operationsmanagement.SolutionProperties{
WorkspaceResourceID: &workspaceID,
},
}

res, err := client.CreateOrUpdate(ctx, resGroup, name, parameters)
//Currently this is required to work around successful creation resulting in an error
// being returned
if err != nil && res.StatusCode != 201 {
return err
}

solution, _ := client.Get(ctx, resGroup, name)

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

d.SetId(*solution.ID)

return resourceArmLogAnalyticsSolutionRead(d, meta)

}

func resourceArmLogAnalyticsSolutionRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).solutionsClient
ctx := meta.(*ArmClient).StopContext
id, err := parseAzureResourceID(d.Id())
if err != nil {
return err
}
resGroup := id.ResourceGroup
name := id.Path["solutions"]

resp, err := client.Get(ctx, 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 solutions '%s': %+v", name, err)
}

if resp.Plan == nil {
return fmt.Errorf("Error making Read request on AzureRM Log Analytics solutions '%s': Plan was nil", name)
}

d.Set("location", resp.Location)
d.Set("resource_group_name", resGroup)

// Reversing the mapping used to get .solution_name
// expecting resp.Name to be in format "SolutionName(WorkspaceName)".
if resp.Name != nil && strings.Contains(*resp.Name, "(") {
if parts := strings.Split(*resp.Name, "("); len(parts) == 2 {
d.Set("solution_name", parts[0])
workspaceName := strings.TrimPrefix(parts[1], "(")
workspaceName = strings.TrimSuffix(workspaceName, ")")
d.Set("workspace_name", workspaceName)
} else {
return fmt.Errorf("Error making Read request on AzureRM Log Analytics solutions '%v': isn't in expected format 'Solution(WorkspaceName)'", resp.Name)
}
} else {
return fmt.Errorf("Error making Read request on AzureRM Log Analytics solutions '%v': isn't in expected format 'Solution(WorkspaceName)'", resp.Name)
}

if props := resp.Properties; props != nil {
d.Set("workspace_resource_id", props.WorkspaceResourceID)
}
if plan := resp.Plan; plan != nil {
d.Set("plan", flattenAzureRmLogAnalyticsSolutionPlan(*resp.Plan))
}
return nil
}

func resourceArmLogAnalyticsSolutionDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).solutionsClient
ctx := meta.(*ArmClient).StopContext
id, err := parseAzureResourceID(d.Id())
if err != nil {
return err
}
resGroup := id.ResourceGroup
name := id.Path["solutions"]

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

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

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

return nil
}

func expandAzureRmLogAnalyticsSolutionPlan(d *schema.ResourceData) operationsmanagement.SolutionPlan {
plans := d.Get("plan").([]interface{})
plan := plans[0].(map[string]interface{})

name := plan["name"].(string)
publisher := plan["publisher"].(string)
promotionCode := plan["promotion_code"].(string)
product := plan["product"].(string)

expandedPlan := operationsmanagement.SolutionPlan{
Name: utils.String(name),
PromotionCode: utils.String(promotionCode),
Publisher: utils.String(publisher),
Product: utils.String(product),
}

return expandedPlan
}

func flattenAzureRmLogAnalyticsSolutionPlan(plan operationsmanagement.SolutionPlan) []interface{} {
plans := make([]interface{}, 0)
values := make(map[string]interface{})

values["name"] = *plan.Name
values["product"] = *plan.Product
values["promotion_code"] = *plan.PromotionCode
values["publisher"] = *plan.Publisher

return append(plans, values)
}
Loading

0 comments on commit 265f47e

Please sign in to comment.