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_mobile_network_attached_data_network; new datasource: azurerm_mobile_network_attached_data_network #22168

Merged
merged 12 commits into from
Jul 21, 2023
6 changes: 6 additions & 0 deletions internal/services/mobilenetwork/client/client.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package client

import (
"github.com/hashicorp/go-azure-sdk/resource-manager/mobilenetwork/2022-11-01/attacheddatanetwork"
"github.com/hashicorp/go-azure-sdk/resource-manager/mobilenetwork/2022-11-01/datanetwork"
"github.com/hashicorp/go-azure-sdk/resource-manager/mobilenetwork/2022-11-01/mobilenetwork"
"github.com/hashicorp/go-azure-sdk/resource-manager/mobilenetwork/2022-11-01/packetcorecontrolplane"
Expand All @@ -23,6 +24,7 @@ type Client struct {
SIMPolicyClient *simpolicy.SIMPolicyClient
PacketCoreControlPlaneClient *packetcorecontrolplane.PacketCoreControlPlaneClient
PacketCoreDataPlaneClient *packetcoredataplane.PacketCoreDataPlaneClient
AttachedDataNetworkClient *attacheddatanetwork.AttachedDataNetworkClient
}

func NewClient(o *common.ClientOptions) *Client {
Expand Down Expand Up @@ -53,6 +55,9 @@ func NewClient(o *common.ClientOptions) *Client {
packetCoreDataPlaneClient := packetcoredataplane.NewPacketCoreDataPlaneClientWithBaseURI(o.ResourceManagerEndpoint)
o.ConfigureClient(&packetCoreDataPlaneClient.Client, o.ResourceManagerAuthorizer)

attachedDataNetworkClient := attacheddatanetwork.NewAttachedDataNetworkClientWithBaseURI(o.ResourceManagerEndpoint)
o.ConfigureClient(&attachedDataNetworkClient.Client, o.ResourceManagerAuthorizer)

return &Client{
MobileNetworkClient: &mobileNetworkClient,
DataNetworkClient: &dataNetworkClient,
Expand All @@ -63,5 +68,6 @@ func NewClient(o *common.ClientOptions) *Client {
SIMPolicyClient: &simPolicyClient,
PacketCoreControlPlaneClient: &packetCoreControlPlaneClient,
PacketCoreDataPlaneClient: &packetCoreDataPlaneClient,
AttachedDataNetworkClient: &attachedDataNetworkClient,
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
package mobilenetwork

import (
"context"
"fmt"
"time"

"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/go-azure-helpers/lang/response"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema"
"github.com/hashicorp/go-azure-helpers/resourcemanager/location"
"github.com/hashicorp/go-azure-sdk/resource-manager/mobilenetwork/2022-11-01/attacheddatanetwork"
"github.com/hashicorp/go-azure-sdk/resource-manager/mobilenetwork/2022-11-01/packetcoredataplane"
"github.com/hashicorp/terraform-provider-azurerm/internal/sdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation"
)

type AttachedDataNetworkDataSource struct{}

var _ sdk.DataSource = AttachedDataNetworkDataSource{}

func (r AttachedDataNetworkDataSource) ResourceType() string {
return "azurerm_mobile_network_attached_data_network"
}

func (r AttachedDataNetworkDataSource) ModelObject() interface{} {
return &AttachedDataNetworkModel{}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The model for the data source should be separately defined to the resource model. Whilst they can be the same, they will often contain different properties so we should always start out with a discrete struct for the data source.

}

func (r AttachedDataNetworkDataSource) IDValidationFunc() pluginsdk.SchemaValidateFunc {
return attacheddatanetwork.ValidateAttachedDataNetworkID
}

func (r AttachedDataNetworkDataSource) Arguments() map[string]*pluginsdk.Schema {
return map[string]*pluginsdk.Schema{
"mobile_network_data_network_name": {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall we rename this to name, or do we want to rename the corresponding field in the model from Name to MobileNetworkDataNetworkName to be consistent?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was marked resolved but I don't see any discussion or explanation, can we have some context?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On reflection, given that this needs to be the same value as the corresponding Mobile Network Data Network's name value, we should in fact use the ID for that here and extract the name from it. This ensures the value is consistent, provides additional validation, and the value can be pulled from a reference allowing an explicit dependency between the resources.

Suggested change
"mobile_network_data_network_name": {
"mobile_network_data_network_id": {

Copy link
Contributor Author

@ziyeqf ziyeqf Jun 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason to use name instead of id is the id format of azurerm_mobile_network_attached_data_network does not contain mobileNetworkName, the response/model does not contain it either... Then we cannot set the id in read func

attached_data_network_id:/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.MobileNetwork/packetCoreControlPlanes/{packetCoreControlPlaneName}/packetCoreDataPlanes/{packetCoreDataPlaneName}/attachedDataNetworks/{attachedDataNetworkName}

data_network_id: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.MobileNetwork/mobileNetworks/{mobileNetworkName}/dataNetworks/{dataNetworkName}

Copy link
Contributor Author

@ziyeqf ziyeqf Jun 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Screenshot 2023-06-29 at 11 15 13

Here is the dependency between these resources, black arrow means dependency, yellow arrow means id path. As there is a N:1 relation between azurerm_mobile_network_site and azurerm_mobile_network_packet_core_control_plane, itt seems there is no way get the id of azurerm_mobile_network_data_network. WDYT?

Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: validation.StringIsNotEmpty,
},

"mobile_network_packet_core_data_plane_id": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: packetcoredataplane.ValidatePacketCoreDataPlaneID,
},
}
}

func (r AttachedDataNetworkDataSource) Attributes() map[string]*pluginsdk.Schema {
return map[string]*pluginsdk.Schema{

"location": commonschema.LocationComputed(),

"dns_addresses": {
Type: pluginsdk.TypeList,
Computed: true,
Elem: &pluginsdk.Schema{
Type: pluginsdk.TypeString,
},
},

"network_address_port_translation": {
Type: pluginsdk.TypeList,
Computed: true,
Elem: &pluginsdk.Resource{
Schema: map[string]*pluginsdk.Schema{
"pinhole_maximum_number": {
Type: pluginsdk.TypeInt,
Optional: true,
},

"icmp_pinhole_timeout_in_seconds": {
Type: pluginsdk.TypeInt,
Computed: true,
},

"tcp_pinhole_timeout_in_seconds": {
Type: pluginsdk.TypeInt,
Computed: true,
},

"udp_pinhole_timeout_in_seconds": {
Type: pluginsdk.TypeInt,
Computed: true,
},

"port_range": {
Type: pluginsdk.TypeList,
Computed: true,
Elem: &pluginsdk.Resource{
Schema: map[string]*pluginsdk.Schema{
"max_port": {
Type: pluginsdk.TypeInt,
Computed: true,
},

"min_port": {
Type: pluginsdk.TypeInt,
Computed: true,
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these just be minimum and maximum, given that they are within a port_range block?

Suggested change
"max_port": {
Type: pluginsdk.TypeInt,
Computed: true,
},
"min_port": {
Type: pluginsdk.TypeInt,
Computed: true,
},
"maximum": {
Type: pluginsdk.TypeInt,
Computed: true,
},
"minimum": {
Type: pluginsdk.TypeInt,
Computed: true,
},

},
},
},

"tcp_port_reuse_minimum_hold_time_in_seconds": {
Type: pluginsdk.TypeInt,
Computed: true,
},

"udp_port_reuse_minimum_hold_time_in_seconds": {
Type: pluginsdk.TypeInt,
Computed: true,
},
},
},
},

"user_plane_access_name": {
Type: pluginsdk.TypeString,
Computed: true,
},

"user_plane_access_ipv4_address": {
Type: pluginsdk.TypeString,
Computed: true,
},

"user_plane_access_ipv4_subnet": {
Type: pluginsdk.TypeString,
Computed: true,
},

"user_plane_access_ipv4_gateway": {
Type: pluginsdk.TypeString,
Computed: true,
},

"user_equipment_address_pool_prefixes": {
Type: pluginsdk.TypeList,
Computed: true,
Elem: &pluginsdk.Schema{
Type: pluginsdk.TypeString,
},
},

"user_equipment_static_address_pool_prefixes": {
Type: pluginsdk.TypeList,
Computed: true,
Elem: &pluginsdk.Schema{
Type: pluginsdk.TypeString,
},
},

"tags": commonschema.TagsDataSource(),
}
}

func (r AttachedDataNetworkDataSource) Read() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 5 * time.Minute,
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
var inputModel AttachedDataNetworkModel
if err := metadata.Decode(&inputModel); err != nil {
return fmt.Errorf("decoding: %+v", err)
}

client := metadata.Client.MobileNetwork.AttachedDataNetworkClient

packetCoreDataPlaneId, err := packetcoredataplane.ParsePacketCoreDataPlaneID(inputModel.MobileNetworkPacketCoreDataPlaneId)
if err != nil {
return err
}

id := attacheddatanetwork.NewAttachedDataNetworkID(packetCoreDataPlaneId.SubscriptionId, packetCoreDataPlaneId.ResourceGroupName, packetCoreDataPlaneId.PacketCoreControlPlaneName, packetCoreDataPlaneId.PacketCoreDataPlaneName, inputModel.Name)
if err != nil {
return err
}

resp, err := client.Get(ctx, id)
if err != nil {
if response.WasNotFound(resp.HttpResponse) {
return metadata.MarkAsGone(id)
}

return fmt.Errorf("retrieving %s: %+v", id, err)
}

state := AttachedDataNetworkModel{
Name: id.AttachedDataNetworkName,
MobileNetworkPacketCoreDataPlaneId: packetcoredataplane.NewPacketCoreDataPlaneID(id.SubscriptionId, id.ResourceGroupName, id.PacketCoreControlPlaneName, id.PacketCoreDataPlaneName).ID(),
}

if model := resp.Model; model != nil {
props := model.Properties

state.Location = location.Normalize(model.Location)
state.DnsAddresses = props.DnsAddresses
state.NaptConfiguration = flattenNaptConfigurationModel(props.NaptConfiguration)
state.UserEquipmentAddressPoolPrefix = pointer.From(props.UserEquipmentAddressPoolPrefix)
state.UserEquipmentStaticAddressPoolPrefix = pointer.From(props.UserEquipmentStaticAddressPoolPrefix)
state.UserPlaneAccessIPv4Address = pointer.From(props.UserPlaneDataInterface.IPv4Address)
state.UserPlaneAccessIPv4Gateway = pointer.From(props.UserPlaneDataInterface.IPv4Gateway)
state.UserPlaneAccessIPv4Subnet = pointer.From(props.UserPlaneDataInterface.IPv4Subnet)
state.UserPlaneAccessName = pointer.From(props.UserPlaneDataInterface.Name)
state.Tags = pointer.From(model.Tags)
}

metadata.SetID(id)

return metadata.Encode(&state)
},
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package mobilenetwork_test

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance"
"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check"
)

type MobileNetworkAttachedDataNetworkDataSource struct{}

func TestAccMobileNetworkAttachedDataNetworkDataSource_basic(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_mobile_network_attached_data_network", "test")
d := MobileNetworkAttachedDataNetworkDataSource{}
data.DataSourceTest(t, []acceptance.TestStep{
{
Config: d.basic(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).Key(`location`).Exists(),
check.That(data.ResourceName).Key(`dns_addresses.0`).HasValue("1.1.1.1"),
check.That(data.ResourceName).Key(`user_equipment_address_pool_prefixes.0`).HasValue("2.4.1.0/24"),
check.That(data.ResourceName).Key(`user_equipment_static_address_pool_prefixes.0`).HasValue("2.4.2.0/24"),
check.That(data.ResourceName).Key(`network_address_port_translation.0.pinhole_maximum_number`).HasValue("65536"),
check.That(data.ResourceName).Key(`network_address_port_translation.0.icmp_pinhole_timeout_in_seconds`).HasValue("30"),
check.That(data.ResourceName).Key(`network_address_port_translation.0.tcp_pinhole_timeout_in_seconds`).HasValue("100"),
check.That(data.ResourceName).Key(`network_address_port_translation.0.udp_pinhole_timeout_in_seconds`).HasValue("39"),
check.That(data.ResourceName).Key(`network_address_port_translation.0.port_range.0.max_port`).HasValue("49999"),
check.That(data.ResourceName).Key(`network_address_port_translation.0.port_range.0.min_port`).HasValue("1024"),
check.That(data.ResourceName).Key(`network_address_port_translation.0.tcp_port_reuse_minimum_hold_time_in_seconds`).HasValue("120"),
check.That(data.ResourceName).Key(`network_address_port_translation.0.udp_port_reuse_minimum_hold_time_in_seconds`).HasValue("60"),
check.That(data.ResourceName).Key(`user_plane_access_name`).HasValue("test"),
check.That(data.ResourceName).Key(`user_plane_access_ipv4_address`).HasValue("10.204.141.4"),
check.That(data.ResourceName).Key(`user_plane_access_ipv4_gateway`).HasValue("10.204.141.1"),
check.That(data.ResourceName).Key(`user_plane_access_ipv4_subnet`).HasValue("10.204.141.0/24"),
check.That(data.ResourceName).Key(`tags.%`).HasValue("1"),
),
},
})
}

func (r MobileNetworkAttachedDataNetworkDataSource) basic(data acceptance.TestData) string {
return fmt.Sprintf(`
%s

data "azurerm_mobile_network_attached_data_network" "test" {
mobile_network_data_network_name = azurerm_mobile_network_attached_data_network.test.mobile_network_data_network_name
mobile_network_packet_core_data_plane_id = azurerm_mobile_network_attached_data_network.test.mobile_network_packet_core_data_plane_id
}
`, MobileNetworkAttachedDataNetworkResource{}.complete(data))
}
Loading