-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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_private_link_endpoint
New Data Source: azurerm_private_link_endpoint_connection
and expose attibute in azurerm_subnet
#4493
Changes from 1 commit
64bb60e
d445539
cf252b9
266fa1b
3840307
7ce24b8
71133ca
f965560
87cb012
3a4b263
fe67c8f
bd69625
5ee333d
57ce715
52fa425
61624f4
d5e8155
07452f5
b24ac15
0d8dcd9
39eef7d
69bb2c0
f0f071d
e9300b9
a676a2f
255957d
06990fc
227ebc9
e0fde44
c0a3c8e
4ba6e4e
817ca0f
33e7fdd
e73e10e
b209b87
bb8a136
ae82096
7ab6a68
261c704
541694f
6d6a38f
d818bc6
017b56c
a8e0eac
527a2f1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package network | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/helper/schema" | ||
) | ||
|
||
func ValidatePrivateLinkEndpointSettings(d *schema.ResourceData) error { | ||
privateServiceConnections := d.Get("private_service_connection").([]interface{}) | ||
|
||
for _, psc := range privateServiceConnections { | ||
privateServiceConnection := psc.(map[string]interface{}) | ||
name := privateServiceConnection["name"].(string) | ||
|
||
// If this is not a manule connection and the message is set return an error since this does not make sense. | ||
if !privateServiceConnection["is_manual_connection"].(bool) && privateServiceConnection["request_message"].(string) != "" { | ||
return fmt.Errorf(`"private_service_connection":%q is invalid, the "request_message" attribute cannot be set if the "is_manual_connection" attribute is "false"`, name) | ||
} | ||
} | ||
|
||
return nil | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -11,6 +11,7 @@ import ( | |||||||||||||||||||||||||
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" | ||||||||||||||||||||||||||
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" | ||||||||||||||||||||||||||
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" | ||||||||||||||||||||||||||
aznet "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network" | ||||||||||||||||||||||||||
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" | ||||||||||||||||||||||||||
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" | ||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||
|
@@ -44,8 +45,55 @@ func resourceArmPrivateLinkEndpoint() *schema.Resource { | |||||||||||||||||||||||||
ValidateFunc: validate.NoEmptyStrings, | ||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
// the 'manual_private_link_service_connection' attribute has been removed | ||||||||||||||||||||||||||
// as the behavior does not make sense in a terraform resource | ||||||||||||||||||||||||||
"private_service_connection": { | ||||||||||||||||||||||||||
Type: schema.TypeList, | ||||||||||||||||||||||||||
Optional: true, | ||||||||||||||||||||||||||
Elem: &schema.Resource{ | ||||||||||||||||||||||||||
Schema: map[string]*schema.Schema{ | ||||||||||||||||||||||||||
"name": { | ||||||||||||||||||||||||||
Type: schema.TypeString, | ||||||||||||||||||||||||||
Required: true, | ||||||||||||||||||||||||||
ValidateFunc: validate.NoEmptyStrings, | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we use regex to validate this? |
||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||
"is_manual_connection": { | ||||||||||||||||||||||||||
Type: schema.TypeBool, | ||||||||||||||||||||||||||
Optional: true, | ||||||||||||||||||||||||||
Default: false, | ||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||
"private_connection_resource_id": { | ||||||||||||||||||||||||||
Type: schema.TypeString, | ||||||||||||||||||||||||||
Required: true, | ||||||||||||||||||||||||||
ValidateFunc: validate.NoEmptyStrings, | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. COuld we validate this is an ID? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please address this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we validate this with RegEx? |
||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||
"subresource_names": { | ||||||||||||||||||||||||||
Type: schema.TypeList, | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we use a TypeSet here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be a type set? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be a type set? |
||||||||||||||||||||||||||
Optional: true, | ||||||||||||||||||||||||||
Elem: &schema.Schema{ | ||||||||||||||||||||||||||
Type: schema.TypeString, | ||||||||||||||||||||||||||
ValidateFunc: validate.NoEmptyStrings, | ||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we validate this is an ID? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is still not validating its an ID? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same thing? |
||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||
"request_message": { | ||||||||||||||||||||||||||
// Only valid if is_manual_connection == true. Restricted to 140 chars. | ||||||||||||||||||||||||||
Type: schema.TypeString, | ||||||||||||||||||||||||||
Optional: true, | ||||||||||||||||||||||||||
ValidateFunc: validate.PrivateLinkEnpointRequestMessage, | ||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||
"provisioning_state": { | ||||||||||||||||||||||||||
// ProvisioningState - The provisioning state of the Private Link Endpoint. Possible values include: 'Succeeded', 'Updating', 'Deleting', 'Failed' | ||||||||||||||||||||||||||
// PrivateLinkServiceConnectionProperties.ProvisioningState | ||||||||||||||||||||||||||
Type: schema.TypeString, | ||||||||||||||||||||||||||
Computed: true, | ||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||
"status": { | ||||||||||||||||||||||||||
// Status - Indicates whether the connection has been Approved/Rejected/Removed by the owner of the service. | ||||||||||||||||||||||||||
// PrivateLinkServiceConnection.PrivateLinkServiceConnectionProperties.PrivateLinkServiceConnectionState.Status | ||||||||||||||||||||||||||
Type: schema.TypeString, | ||||||||||||||||||||||||||
Computed: true, | ||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
"network_interface_ids": { | ||||||||||||||||||||||||||
Type: schema.TypeList, | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we make this a TypeSet? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. THis should be a |
||||||||||||||||||||||||||
|
@@ -67,11 +115,15 @@ func resourceArmPrivateLinkEndpointCreateUpdate(d *schema.ResourceData, meta int | |||||||||||||||||||||||||
name := d.Get("name").(string) | ||||||||||||||||||||||||||
resourceGroup := d.Get("resource_group_name").(string) | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
if err := aznet.ValidatePrivateLinkEndpointSettings(d); err != nil { | ||||||||||||||||||||||||||
return fmt.Errorf("Error validating the configuration for the Private Link Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
if features.ShouldResourcesBeImported() && d.IsNewResource() { | ||||||||||||||||||||||||||
resp, err := client.Get(ctx, resourceGroup, name, "") | ||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||
if !utils.ResponseWasNotFound(resp.Response) { | ||||||||||||||||||||||||||
return fmt.Errorf("Error checking for present of existing Private Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) | ||||||||||||||||||||||||||
return fmt.Errorf("Error checking for present of existing Private Link Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
if !utils.ResponseWasNotFound(resp.Response) { | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is incorrect
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed. |
||||||||||||||||||||||||||
|
@@ -80,12 +132,15 @@ func resourceArmPrivateLinkEndpointCreateUpdate(d *schema.ResourceData, meta int | |||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
location := azure.NormalizeLocation(d.Get("location").(string)) | ||||||||||||||||||||||||||
privateServiceConnections := d.Get("private_service_connection").([]interface{}) | ||||||||||||||||||||||||||
subnetId := d.Get("subnet_id").(string) | ||||||||||||||||||||||||||
t := d.Get("tags").(map[string]interface{}) | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
parameters := network.PrivateEndpoint{ | ||||||||||||||||||||||||||
Location: utils.String(location), | ||||||||||||||||||||||||||
PrivateEndpointProperties: &network.PrivateEndpointProperties{ | ||||||||||||||||||||||||||
PrivateLinkServiceConnections: expandArmPrivateLinkEndpointServiceConnection(privateServiceConnections, false), | ||||||||||||||||||||||||||
ManualPrivateLinkServiceConnections: expandArmPrivateLinkEndpointServiceConnection(privateServiceConnections, true), | ||||||||||||||||||||||||||
Subnet: &network.Subnet{ | ||||||||||||||||||||||||||
ID: utils.String(subnetId), | ||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||
|
@@ -95,19 +150,19 @@ func resourceArmPrivateLinkEndpointCreateUpdate(d *schema.ResourceData, meta int | |||||||||||||||||||||||||
|
||||||||||||||||||||||||||
future, err := client.CreateOrUpdate(ctx, resourceGroup, name, parameters) | ||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||
return fmt.Errorf("Error creating Private Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) | ||||||||||||||||||||||||||
return fmt.Errorf("Error creating Private Link Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { | ||||||||||||||||||||||||||
return fmt.Errorf("Error waiting for creation of Private Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) | ||||||||||||||||||||||||||
return fmt.Errorf("Error waiting for creation of Private Link Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
resp, err := client.Get(ctx, resourceGroup, name, "") | ||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||
return fmt.Errorf("Error retrieving Private Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) | ||||||||||||||||||||||||||
return fmt.Errorf("Error retrieving Private Link Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
if resp.ID == nil || *resp.ID == "" { | ||||||||||||||||||||||||||
return fmt.Errorf("API returns a nil/empty id on Private Link Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
if resp.ID == nil || *resp.ID == "" { | ||||||||||||||||||||||||||
return fmt.Errorf("API returns a nil/empty id on Private Link Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
d.SetId(*resp.ID) | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
return resourceArmPrivateLinkEndpointRead(d, meta) | ||||||||||||||||||||||||||
|
@@ -127,11 +182,11 @@ func resourceArmPrivateLinkEndpointRead(d *schema.ResourceData, meta interface{} | |||||||||||||||||||||||||
resp, err := client.Get(ctx, resourceGroup, name, "") | ||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||
if utils.ResponseWasNotFound(resp.Response) { | ||||||||||||||||||||||||||
log.Printf("[INFO] Private Endpoint %q does not exist - removing from state", d.Id()) | ||||||||||||||||||||||||||
log.Printf("[INFO] Private Link Endpoint %q does not exist - removing from state", d.Id()) | ||||||||||||||||||||||||||
d.SetId("") | ||||||||||||||||||||||||||
return nil | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
return fmt.Errorf("Error reading Private Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) | ||||||||||||||||||||||||||
return fmt.Errorf("Error reading Private Link Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
d.Set("name", resp.Name) | ||||||||||||||||||||||||||
|
@@ -169,18 +224,86 @@ func resourceArmPrivateLinkEndpointDelete(d *schema.ResourceData, meta interface | |||||||||||||||||||||||||
if response.WasNotFound(future.Response()) { | ||||||||||||||||||||||||||
return nil | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
return fmt.Errorf("Error deleting Private Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) | ||||||||||||||||||||||||||
return fmt.Errorf("Error deleting Private Link Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { | ||||||||||||||||||||||||||
if !response.WasNotFound(future.Response()) { | ||||||||||||||||||||||||||
return fmt.Errorf("Error waiting for deleting Private Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) | ||||||||||||||||||||||||||
return fmt.Errorf("Error waiting for deleting Private Link Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
return nil | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
func expandArmPrivateLinkEndpointServiceConnection(input []interface{}, parseManual bool) *[]network.PrivateLinkServiceConnection { | ||||||||||||||||||||||||||
results := make([]network.PrivateLinkServiceConnection, 0) | ||||||||||||||||||||||||||
for _, item := range input { | ||||||||||||||||||||||||||
v := item.(map[string]interface{}) | ||||||||||||||||||||||||||
privateConnectonResourceId := v["private_connection_resource_id"].(string) | ||||||||||||||||||||||||||
subresourceNames := v["subresource_names"].([]interface{}) | ||||||||||||||||||||||||||
requestMessage := v["request_message"].(string) | ||||||||||||||||||||||||||
isManual := v["is_manual_connection"].(bool) | ||||||||||||||||||||||||||
name := v["name"].(string) | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
if isManual == parseManual { | ||||||||||||||||||||||||||
result := network.PrivateLinkServiceConnection{ | ||||||||||||||||||||||||||
Name: utils.String(name), | ||||||||||||||||||||||||||
PrivateLinkServiceConnectionProperties: &network.PrivateLinkServiceConnectionProperties{ | ||||||||||||||||||||||||||
GroupIds: utils.ExpandStringSlice(subresourceNames), | ||||||||||||||||||||||||||
PrivateLinkServiceID: utils.String(privateConnectonResourceId), | ||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
if requestMessage != "" { | ||||||||||||||||||||||||||
result.PrivateLinkServiceConnectionProperties.RequestMessage = utils.String(requestMessage) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
results = append(results, result) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
return &results | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
func flattenArmPrivateLinkEndpointServiceConnection(input *[]network.PrivateLinkServiceConnection) []interface{} { | ||||||||||||||||||||||||||
results := make([]interface{}, 0) | ||||||||||||||||||||||||||
if input == nil { | ||||||||||||||||||||||||||
return results | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
for _, item := range *input { | ||||||||||||||||||||||||||
v := make(map[string]interface{}) | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
if name := item.Name; name != nil { | ||||||||||||||||||||||||||
v["name"] = *name | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
if props := item.PrivateLinkServiceConnectionProperties; props != nil { | ||||||||||||||||||||||||||
if subresourceNames := props.GroupIds; subresourceNames != nil { | ||||||||||||||||||||||||||
v["subresource_names"] = utils.FlattenStringSlice(subresourceNames) | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. looks like this should be called There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I changed the name because it was confusing as to what data it was expecting, here are the strings that are valid here:
|
||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
if privateConnectionResourceId := props.PrivateLinkServiceID; privateConnectionResourceId != nil { | ||||||||||||||||||||||||||
v["private_connection_resource_id"] = *privateConnectionResourceId | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
if requestMessage := props.RequestMessage; requestMessage != nil { | ||||||||||||||||||||||||||
v["request_message"] = *requestMessage | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
if provisioningState := props.ProvisioningState; provisioningState != "" { | ||||||||||||||||||||||||||
v["provisioning_state"] = provisioningState | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
katbyte marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||
if s := props.PrivateLinkServiceConnectionState; s != nil { | ||||||||||||||||||||||||||
if status := s.Status; status != nil { | ||||||||||||||||||||||||||
v["status"] = *status | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
katbyte marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
results = append(results, v) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
return results | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
func flattenArmPrivateLinkEndpointInterface(input *[]network.Interface) []interface{} { | ||||||||||||||||||||||||||
if input == nil { | ||||||||||||||||||||||||||
return make([]interface{}, 0) | ||||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we validate this is a proper ID?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please address this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.