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

azurerm_app_service_connection: add support for scope, configuration_info and public_network_solution #26387

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
116 changes: 102 additions & 14 deletions internal/services/serviceconnector/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (

"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonids"
"github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links"
"github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2024-04-01/servicelinker"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/storage/parse"
Expand All @@ -31,6 +30,19 @@ type SecretStoreModel struct {
KeyVaultId string `tfschema:"key_vault_id"`
}

type ConfigurationInfo struct {
Action string `tfschema:"action"`
ConfigurationStore []ConfigurationStore `tfschema:"configuration_store"`
}

type ConfigurationStore struct {
AppConfigurationId string `tfschema:"app_configuration_id"`
}

type PublicNetworkSolution struct {
Action string `tfschema:"action"`
}

func secretStoreSchema() *pluginsdk.Schema {
return &pluginsdk.Schema{
Type: pluginsdk.TypeList,
Expand Down Expand Up @@ -156,7 +168,7 @@ func expandServiceConnectorAuthInfoForCreate(input []AuthInfoModel) (servicelink
return nil, fmt.Errorf("unrecognised authentication type: %q", in.Type)
}

func expandServiceConnectorAuthInfoForUpdate(input []AuthInfoModel) (links.AuthInfoBase, error) {
func expandServiceConnectorAuthInfoForUpdate(input []AuthInfoModel) (servicelinker.AuthInfoBase, error) {
if err := validateServiceConnectorAuthInfo(input); err != nil {
return nil, err
}
Expand All @@ -166,34 +178,34 @@ func expandServiceConnectorAuthInfoForUpdate(input []AuthInfoModel) (links.AuthI
}

in := input[0]
switch links.AuthType(in.Type) {
case links.AuthTypeSecret:
return links.SecretAuthInfo{
switch servicelinker.AuthType(in.Type) {
case servicelinker.AuthTypeSecret:
return servicelinker.SecretAuthInfo{
Name: pointer.To(in.Name),
SecretInfo: links.ValueSecretInfo{
SecretInfo: servicelinker.ValueSecretInfo{
Value: pointer.To(in.Secret),
},
}, nil

case links.AuthTypeServicePrincipalSecret:
return links.ServicePrincipalSecretAuthInfo{
case servicelinker.AuthTypeServicePrincipalSecret:
return servicelinker.ServicePrincipalSecretAuthInfo{
ClientId: in.ClientId,
PrincipalId: in.PrincipalId,
Secret: in.Secret,
}, nil

case links.AuthTypeServicePrincipalCertificate:
return links.ServicePrincipalCertificateAuthInfo{
case servicelinker.AuthTypeServicePrincipalCertificate:
return servicelinker.ServicePrincipalCertificateAuthInfo{
Certificate: in.Certificate,
ClientId: in.ClientId,
PrincipalId: in.PrincipalId,
}, nil

case links.AuthTypeSystemAssignedIdentity:
return links.SystemAssignedIdentityAuthInfo{}, nil
case servicelinker.AuthTypeSystemAssignedIdentity:
return servicelinker.SystemAssignedIdentityAuthInfo{}, nil

case links.AuthTypeUserAssignedIdentity:
return links.UserAssignedIdentityAuthInfo{
case servicelinker.AuthTypeUserAssignedIdentity:
return servicelinker.UserAssignedIdentityAuthInfo{
ClientId: pointer.To(in.ClientId),
SubscriptionId: pointer.To(in.SubscriptionId),
}, nil
Expand Down Expand Up @@ -308,6 +320,82 @@ func expandSecretStore(input []SecretStoreModel) *servicelinker.SecretStore {
}
}

func expandConfigurationInfo(input []ConfigurationInfo) *servicelinker.ConfigurationInfo {
if len(input) == 0 {
return nil
}
v := input[0]
action := servicelinker.ActionType(v.Action)
configurationStore := expandConfigurationStore(v.ConfigurationStore)

return &servicelinker.ConfigurationInfo{
Action: pointer.To(action),
ConfigurationStore: configurationStore,
}
}

func expandConfigurationStore(input []ConfigurationStore) *servicelinker.ConfigurationStore {
if len(input) == 0 {
return nil
}
v := input[0]

appConfigurationId := v.AppConfigurationId
return &servicelinker.ConfigurationStore{
AppConfigurationId: utils.String(appConfigurationId),
}
}

func expandPublicNetworkSolution(input []PublicNetworkSolution) *servicelinker.PublicNetworkSolution {
if len(input) == 0 {
return nil
}
v := input[0]

action := v.Action
return &servicelinker.PublicNetworkSolution{
Action: pointer.To(servicelinker.ActionType(action)),
}
}

func flattenConfigurationInfo(input servicelinker.ConfigurationInfo) []ConfigurationInfo {
var action string
var configurationStore []ConfigurationStore

if input.Action != nil {
action = string(*input.Action)
}

if input.ConfigurationStore != nil {
configurationStore = []ConfigurationStore{
{
AppConfigurationId: pointer.From(input.ConfigurationStore.AppConfigurationId),
},
}
}

return []ConfigurationInfo{
{
Action: action,
ConfigurationStore: configurationStore,
},
}
}

func flattenPublicNetworkSolution(input servicelinker.PublicNetworkSolution) []PublicNetworkSolution {
var action string

if input.Action != nil {
action = string(*input.Action)
}

return []PublicNetworkSolution{
{
Action: action,
},
}
}

func flattenServiceConnectorAuthInfo(input servicelinker.AuthInfoBase, pwd string) []AuthInfoModel {
var authType string
var name string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,16 @@ var _ sdk.ResourceWithUpdate = AppServiceConnectorResource{}
type AppServiceConnectorResource struct{}

type AppServiceConnectorResourceModel struct {
Name string `tfschema:"name"`
AppServiceId string `tfschema:"app_service_id"`
TargetResourceId string `tfschema:"target_resource_id"`
ClientType string `tfschema:"client_type"`
AuthInfo []AuthInfoModel `tfschema:"authentication"`
VnetSolution string `tfschema:"vnet_solution"`
SecretStore []SecretStoreModel `tfschema:"secret_store"`
Name string `tfschema:"name"`
AppServiceId string `tfschema:"app_service_id"`
TargetResourceId string `tfschema:"target_resource_id"`
ClientType string `tfschema:"client_type"`
AuthInfo []AuthInfoModel `tfschema:"authentication"`
VnetSolution string `tfschema:"vnet_solution"`
SecretStore []SecretStoreModel `tfschema:"secret_store"`
Scope string `tfschema:"scope"`
ConfigurationInfo []ConfigurationInfo `tfschema:"configuration"`
PublicNetworkSolution []PublicNetworkSolution `tfschema:"public_network_solution"`
}

func (r AppServiceConnectorResource) Arguments() map[string]*schema.Schema {
Expand Down Expand Up @@ -89,6 +92,62 @@ func (r AppServiceConnectorResource) Arguments() map[string]*schema.Schema {
},

"authentication": authInfoSchema(),

"scope": {
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validation.StringIsNotEmpty,
},

"configuration": {
Type: pluginsdk.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"action": {
Type: pluginsdk.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{
string(servicelinker.ActionTypeOptOut),
string(servicelinker.ActionTypeEnable),
}, false),
},

"configuration_store": {
Type: pluginsdk.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"app_configuration_id": {
Type: pluginsdk.TypeString,
Optional: true,
},
},
},
},
},
},
},

"public_network_solution": {
Type: pluginsdk.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"action": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{
string(servicelinker.ActionTypeOptOut),
string(servicelinker.ActionTypeEnable),
}, false),
},
},
},
},
jackofallops marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down Expand Up @@ -163,6 +222,18 @@ func (r AppServiceConnectorResource) Create() sdk.ResourceFunc {
serviceConnectorProperties.VNetSolution = &vNetSolution
}

if model.Scope != "" {
serviceConnectorProperties.Scope = pointer.To(model.Scope)
}

if model.ConfigurationInfo != nil {
serviceConnectorProperties.ConfigurationInfo = expandConfigurationInfo(model.ConfigurationInfo)
}

if model.PublicNetworkSolution != nil {
serviceConnectorProperties.PublicNetworkSolution = expandPublicNetworkSolution(model.PublicNetworkSolution)
}

props := servicelinker.LinkerResource{
Id: utils.String(id.ID()),
Name: utils.String(model.Name),
Expand Down Expand Up @@ -224,6 +295,16 @@ func (r AppServiceConnectorResource) Read() sdk.ResourceFunc {
state.SecretStore = flattenSecretStore(*props.SecretStore)
}

state.Scope = pointer.From(props.Scope)

if props.ConfigurationInfo != nil {
state.ConfigurationInfo = flattenConfigurationInfo(pointer.From(props.ConfigurationInfo))
}

if props.PublicNetworkSolution != nil {
state.PublicNetworkSolution = flattenPublicNetworkSolution(pointer.From(props.PublicNetworkSolution))
}

return metadata.Encode(&state)
}
return nil
Expand Down Expand Up @@ -256,8 +337,8 @@ func (r AppServiceConnectorResource) Update() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 30 * time.Minute,
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.ServiceConnector.LinksClient
id, err := links.ParseScopedLinkerID(metadata.ResourceData.Id())
client := metadata.Client.ServiceConnector.ServiceLinkerClient
id, err := servicelinker.ParseScopedLinkerID(metadata.ResourceData.Id())
if err != nil {
return err
}
Expand All @@ -267,24 +348,29 @@ func (r AppServiceConnectorResource) Update() sdk.ResourceFunc {
return fmt.Errorf("decoding %+v", err)
}

linkerProps := links.LinkerProperties{}
existing, err := client.LinkerGet(ctx, *id)
if err != nil {
return fmt.Errorf("checking for presence of existing %s: %+v", *id, err)
}
linkerProps := existing.Model.Properties
d := metadata.ResourceData

linkerProps.TargetService = servicelinker.AzureResource{
Id: pointer.To(state.TargetResourceId),
}
if d.HasChange("client_type") {
clientType := links.ClientType(state.ClientType)
linkerProps.ClientType = &clientType
linkerProps.ClientType = pointer.To(servicelinker.ClientType(state.ClientType))
}

if d.HasChange("vnet_solution") {
vnetSolutionType := links.VNetSolutionType(state.VnetSolution)
vnetSolution := links.VNetSolution{
Type: &vnetSolutionType,
vnetSolution := servicelinker.VNetSolution{
Type: pointer.To(servicelinker.VNetSolutionType(state.VnetSolution)),
}
linkerProps.VNetSolution = &vnetSolution
linkerProps.VNetSolution = pointer.To(vnetSolution)
}

if d.HasChange("secret_store") {
linkerProps.SecretStore = pointer.To(links.SecretStore{KeyVaultId: expandSecretStore(state.SecretStore).KeyVaultId})
linkerProps.SecretStore = pointer.To(servicelinker.SecretStore{KeyVaultId: expandSecretStore(state.SecretStore).KeyVaultId})
}

if d.HasChange("authentication") {
Expand All @@ -296,11 +382,23 @@ func (r AppServiceConnectorResource) Update() sdk.ResourceFunc {
linkerProps.AuthInfo = authInfo
}

props := links.LinkerPatch{
Properties: &linkerProps,
if d.HasChange("scope") {
linkerProps.Scope = pointer.To(state.Scope)
}

if d.HasChange("configuration") {
linkerProps.ConfigurationInfo = expandConfigurationInfo(state.ConfigurationInfo)
}

if d.HasChange("public_network_solution") {
linkerProps.PublicNetworkSolution = expandPublicNetworkSolution(state.PublicNetworkSolution)
}

props := servicelinker.LinkerResource{
Properties: linkerProps,
}

if err := client.LinkerUpdateThenPoll(ctx, *id, props); err != nil {
if err := client.LinkerCreateOrUpdateThenPoll(ctx, *id, props); err != nil {
return fmt.Errorf("updating %s: %+v", *id, err)
}

Expand Down
Loading
Loading