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

New Resource azurerm_app_service_hybrid_connection #7224

Merged
merged 5 commits into from Jun 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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)
jackofallops marked this conversation as resolved.
Show resolved Hide resolved

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
}