Skip to content

Commit

Permalink
Merge pull request #7224 from terraform-providers/r/app-service-hybri…
Browse files Browse the repository at this point in the history
…d-connection
  • Loading branch information
jackofallops committed Jun 9, 2020
2 parents cd55c1b + 0085802 commit 55d4775
Show file tree
Hide file tree
Showing 7 changed files with 754 additions and 0 deletions.
52 changes: 52 additions & 0 deletions azurerm/internal/services/web/app_service_hybrid_connection.go
@@ -0,0 +1,52 @@
package web

import (
"fmt"

"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure"
)

type AppServiceHybridConnectionResourceID struct {
ResourceGroup string
Name string
AppName string
Namespace string
}

func ParseAppServiceHybridConnectionID(input string) (*AppServiceHybridConnectionResourceID, error) {
id, err := azure.ParseAzureResourceID(input)
if err != nil {
return nil, fmt.Errorf("[ERROR] Unable to parse Hybrid Connection ID %q: %+v", input, err)
}

hybridConnection := AppServiceHybridConnectionResourceID{
ResourceGroup: id.ResourceGroup,
}
if hybridConnection.Name, err = id.PopSegment("relays"); err != nil {
return nil, err
}

if hybridConnection.AppName, err = id.PopSegment("sites"); err != nil {
return nil, err
}

if hybridConnection.Namespace, err = id.PopSegment("hybridConnectionNamespaces"); err != nil {
return nil, err
}

return &hybridConnection, nil
}

func ValidateAppServiceHybridConnectionID(i interface{}, k string) (warnings []string, errors []error) {
v, ok := i.(string)
if !ok {
errors = append(errors, fmt.Errorf("expected type of %q to be string", k))
return
}

if _, err := ParseAppServiceHybridConnectionID(v); err != nil {
errors = append(errors, fmt.Errorf("Can not parse %q as a resource id: %v", k, err))
}

return warnings, errors
}
@@ -0,0 +1,232 @@
package web

import (
"fmt"
"log"
"time"

"github.com/Azure/azure-sdk-for-go/services/web/mgmt/2019-08-01/web"
"github.com/hashicorp/go-azure-helpers/response"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"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/tf"
azValidate "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/relay"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/web/validate"
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 resourceArmAppServiceHybridConnection() *schema.Resource {
return &schema.Resource{
Create: resourceArmAppServiceHybridConnectionCreateUpdate,
Read: resourceArmAppServiceHybridConnectionRead,
Update: resourceArmAppServiceHybridConnectionCreateUpdate,
Delete: resourceArmAppServiceHybridConnectionDelete,

Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error {
_, err := ParseAppServiceHybridConnectionID(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{
"app_service_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validate.AppServiceName,
},

"resource_group_name": azure.SchemaResourceGroupName(),

"relay_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: relay.ValidateHybridConnectionID,
},

"hostname": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringIsNotEmpty,
},

"port": {
Type: schema.TypeInt,
Required: true,
ValidateFunc: azValidate.PortNumberOrZero,
},

"send_key_name": {
Type: schema.TypeString,
Optional: true,
Default: "RootManageSharedAccessKey",
ValidateFunc: validation.StringIsNotEmpty,
},

"namespace_name": {
Type: schema.TypeString,
Computed: true,
},

"relay_name": {
Type: schema.TypeString,
Computed: true,
},

"service_bus_namespace": {
Type: schema.TypeString,
Computed: true,
},

"service_bus_suffix": {
Type: schema.TypeString,
Computed: true,
},

"send_key_value": {
Type: schema.TypeString,
Sensitive: true,
Computed: true,
},
},
}
}

func resourceArmAppServiceHybridConnectionCreateUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Web.AppServicesClient
ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d)
defer cancel()

name := d.Get("app_service_name").(string)
resourceGroup := d.Get("resource_group_name").(string)
relayArmURI := d.Get("relay_id").(string)
relayId, err := relay.ParseHybridConnectionID(relayArmURI)
if err != nil {
return fmt.Errorf("Error parsing relay ID %q: %s", relayArmURI, err)
}
namespaceName := relayId.NamespaceName
relayName := relayId.Name

if d.IsNewResource() {
existing, err := client.GetHybridConnection(ctx, resourceGroup, name, namespaceName, relayName)
if err != nil {
if !utils.ResponseWasNotFound(existing.Response) {
return fmt.Errorf("Error checking for presence of existing App Service Hybrid Connection %q (Resource Group %q, Namespace %q, Relay Name %q): %s", name, resourceGroup, namespaceName, relayName, err)
}
}

if existing.ID != nil && *existing.ID != "" {
return tf.ImportAsExistsError("azurerm_app_service_hybrid_connection", *existing.ID)
}
}

port := int32(d.Get("port").(int))

connectionEnvelope := web.HybridConnection{
HybridConnectionProperties: &web.HybridConnectionProperties{
RelayArmURI: &relayArmURI,
Hostname: utils.String(d.Get("hostname").(string)),
Port: &port,
SendKeyName: utils.String(d.Get("send_key_name").(string)),
SendKeyValue: utils.String(""), // The service creates this no matter what is sent, but the API requires the field to be set
},
}

hybridConnection, err := client.CreateOrUpdateHybridConnection(ctx, resourceGroup, name, namespaceName, relayName, connectionEnvelope)
if err != nil {
return fmt.Errorf("failed creating App Service Hybrid Connection %q (resource group %q): %s", name, resourceGroup, err)
}

if hybridConnection.ID == nil && *hybridConnection.ID == "" {
return fmt.Errorf("failed to read ID for Hybrid Connection %q", name)
}
d.SetId(*hybridConnection.ID)

return resourceArmAppServiceHybridConnectionRead(d, meta)
}

func resourceArmAppServiceHybridConnectionRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Web.AppServicesClient
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

id, err := azure.ParseAzureResourceID(d.Id())
if err != nil {
return err
}
resourceGroup := id.ResourceGroup
name := id.Path["sites"]
namespaceName := id.Path["hybridConnectionNamespaces"]
relayName := id.Path["relays"]

resp, err := client.GetHybridConnection(ctx, resourceGroup, name, namespaceName, relayName)
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
log.Printf("[DEBUG] Hybrid Connection for App Service %q (resource group %q) was not found - removing from state", name, resourceGroup)
d.SetId("")
return nil
}
return fmt.Errorf("Error making Read request on App Service Hybrid Connection %q in Namespace %q, Resource Group %q: %s", name, namespaceName, resourceGroup, err)
}
d.Set("app_service_name", name)
d.Set("resource_group_name", resourceGroup)
d.Set("namespace_name", namespaceName)
d.Set("relay_name", relayName)

if props := resp.HybridConnectionProperties; props != nil {
d.Set("port", resp.Port)
d.Set("service_bus_namespace", resp.ServiceBusNamespace)
d.Set("send_key_name", resp.SendKeyName)
d.Set("service_bus_suffix", resp.ServiceBusSuffix)
d.Set("relay_id", resp.RelayArmURI)
d.Set("hostname", resp.Hostname)
}

// key values are not returned in the response, so we get the primary key from the relay namespace ListKeys func
relayNSClient := meta.(*clients.Client).Relay.NamespacesClient
accessKeys, err := relayNSClient.ListKeys(ctx, resourceGroup, *resp.ServiceBusNamespace, *resp.SendKeyName)
if err != nil {
return fmt.Errorf("unable to List Access Keys for Namespace %q (Resource Group %q): %+v", *resp.ServiceBusNamespace, resourceGroup, err)
} else {
d.Set("send_key_value", accessKeys.PrimaryKey)
}

return nil
}

func resourceArmAppServiceHybridConnectionDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Web.AppServicesClient
ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d)
defer cancel()

id, err := azure.ParseAzureResourceID(d.Id())
if err != nil {
return err
}
resourceGroup := id.ResourceGroup
name := id.Path["sites"]
namespaceName := id.Path["hybridConnectionNamespaces"]
relayName := id.Path["relays"]

resp, err := client.DeleteHybridConnection(ctx, resourceGroup, name, namespaceName, relayName)
if err != nil {
if !response.WasNotFound(resp.Response) {
return nil
}
return fmt.Errorf("Error deleting App Service Hybrid Connection %q (Resource Group %q, Relay %q): %+v", name, resourceGroup, relayName, err)
}

return nil
}

0 comments on commit 55d4775

Please sign in to comment.