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_subscription - Add support for adding MPA (Microsoft Partner Agreement) accounts #13723

Merged
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions internal/services/billing/billing_mpa_account_data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package billing

import (
"fmt"
"time"

"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation"
)

func dataSourceBillingMPAAccountScope() *pluginsdk.Resource {
return &pluginsdk.Resource{
Read: dataSourceBillingMPAAccountRead,

Timeouts: &pluginsdk.ResourceTimeout{
Read: pluginsdk.DefaultTimeout(5 * time.Minute),
},

Schema: map[string]*pluginsdk.Schema{
"billing_account_name": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: validation.StringIsNotEmpty,
},

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

func dataSourceBillingMPAAccountRead(d *pluginsdk.ResourceData, meta interface{}) error {
// (@jackofallops) - This is a helper Data Source until the Billing API is usable in the Azure SDK
billingScopeMPAFmt := "/providers/Microsoft.Billing/billingAccounts/%s/customers/%s"

d.SetId(fmt.Sprintf(billingScopeMPAFmt, d.Get("billing_account_name").(string), d.Get("customer_name").(string)))
return nil
}
38 changes: 38 additions & 0 deletions internal/services/billing/billing_mpa_account_data_source_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package billing_test

import (
"testing"

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

type BillingMPAAccountDataSource struct{}

func TestAccBillingMPAAccountDataSource_basic(t *testing.T) {
data := acceptance.BuildTestData(t, "data.azurerm_billing_mpa_account_scope", "test")

r := BillingMPAAccountDataSource{}

data.DataSourceTest(t, []acceptance.TestStep{
{
Config: r.basic(),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).Key("id").HasValue("/providers/Microsoft.Billing/billingAccounts/e879cf0f-2b4d-5431-109a-f72fc9868693:024cabf4-7321-4cf9-be59-df0c77ca51de_2019-05-31/customers/2281f543-7321-4cf9-1e23-edb4Oc31a31c"),
),
},
})
}

func (BillingMPAAccountDataSource) basic() string {
return `
provider "azurerm" {
features {}
}

data "azurerm_billing_mpa_account_scope" "test" {
billing_account_name = "e879cf0f-2b4d-5431-109a-f72fc9868693:024cabf4-7321-4cf9-be59-df0c77ca51de_2019-05-31"
customer_name = "2281f543-7321-4cf9-1e23-edb4Oc31a31c"
}
`
}
57 changes: 57 additions & 0 deletions internal/services/billing/parse/mpa_billing_scope.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package parse

import (
"fmt"
"strings"

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

type MicrosoftPartnerAccountBillingScopeId struct {
BillingAccountName string
CustomerName string
}

func NewMPABillingScopeID(billingAccountName, customerName string) MicrosoftPartnerAccountBillingScopeId {
return MicrosoftPartnerAccountBillingScopeId{
BillingAccountName: billingAccountName,
CustomerName: customerName,
}
}

func (id MicrosoftPartnerAccountBillingScopeId) String() string {
segments := []string{
fmt.Sprintf("Customer Name %q", id.CustomerName),
fmt.Sprintf("Billing Account Name %q", id.BillingAccountName),
}
segmentsStr := strings.Join(segments, " / ")
return fmt.Sprintf("%s: (%s)", "M P A Billing Scope", segmentsStr)
}

func (id MicrosoftPartnerAccountBillingScopeId) ID() string {
fmtString := "/providers/Microsoft.Billing/billingAccounts/%s/customers/%s"
return fmt.Sprintf(fmtString, id.BillingAccountName, id.CustomerName)
}

// MicrosoftPartnerAccountBillingScopeID parses a MPABillingScope ID into an MicrosoftPartnerAccountBillingScopeId struct
func MicrosoftPartnerAccountBillingScopeID(input string) (*MicrosoftPartnerAccountBillingScopeId, error) {
id, err := azure.ParseAzureResourceIDWithoutSubscription(input)
if err != nil {
return nil, err
}

resourceId := MicrosoftPartnerAccountBillingScopeId{}

if resourceId.BillingAccountName, err = id.PopSegment("billingAccounts"); err != nil {
return nil, err
}
if resourceId.CustomerName, err = id.PopSegment("customers"); err != nil {
return nil, err
}

if err := id.ValidateNoEmptySegments(input); err != nil {
return nil, err
}

return &resourceId, nil
}
94 changes: 94 additions & 0 deletions internal/services/billing/parse/mpa_billing_scope_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package parse

import (
"testing"

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

var _ resourceid.Formatter = MicrosoftPartnerAccountBillingScopeId{}

func TestMicrosoftPartnerAccountBillingScopeIDFormatter(t *testing.T) {
actual := NewMPABillingScopeID("e879cf0f-2b4d-5431-109a-f72fc9868693:024cabf4-7321-4cf9-be59-df0c77ca51de_2019-05-31", "2281f543-7321-4cf9-1e23-edb4Oc31a31c").ID()
expected := "/providers/Microsoft.Billing/billingAccounts/e879cf0f-2b4d-5431-109a-f72fc9868693:024cabf4-7321-4cf9-be59-df0c77ca51de_2019-05-31/customers/2281f543-7321-4cf9-1e23-edb4Oc31a31c"
if actual != expected {
t.Fatalf("Expected %q but got %q", expected, actual)
}
}

func TestMicrosoftPartnerAccountBillingScopeID(t *testing.T) {
testData := []struct {
Input string
Error bool
Expected *MicrosoftPartnerAccountBillingScopeId
}{

{
// empty
Input: "",
Error: true,
},

{
// missing BillingAccountName
Input: "/providers/Microsoft.Billing/",
Error: true,
},

{
// missing value for BillingAccountName
Input: "/providers/Microsoft.Billing/billingAccounts/",
Error: true,
},

{
// missing CustomerName
Input: "/providers/Microsoft.Billing/billingAccounts/e879cf0f-2b4d-5431-109a-f72fc9868693:024cabf4-7321-4cf9-be59-df0c77ca51de_2019-05-31/",
Error: true,
},

{
// missing value for CustomerName
Input: "/providers/Microsoft.Billing/billingAccounts/e879cf0f-2b4d-5431-109a-f72fc9868693:024cabf4-7321-4cf9-be59-df0c77ca51de_2019-05-31/customers/",
Error: true,
},

{
// valid
Input: "/providers/Microsoft.Billing/billingAccounts/e879cf0f-2b4d-5431-109a-f72fc9868693:024cabf4-7321-4cf9-be59-df0c77ca51de_2019-05-31/customers/2281f543-7321-4cf9-1e23-edb4Oc31a31c",
Expected: &MicrosoftPartnerAccountBillingScopeId{
BillingAccountName: "e879cf0f-2b4d-5431-109a-f72fc9868693:024cabf4-7321-4cf9-be59-df0c77ca51de_2019-05-31",
CustomerName: "2281f543-7321-4cf9-1e23-edb4Oc31a31c",
},
},

{
// upper-cased
Input: "/PROVIDERS/MICROSOFT.BILLING/BILLINGACCOUNTS/E879CF0F-2B4D-5431-109A-F72FC9868693:024CABF4-7321-4CF9-BE59-DF0C77CA51DE_2019-05-31/CUSTOMERS/2281F543-7321-4CF9-1E23-EDB4OC31A31C",
Error: true,
},
}

for _, v := range testData {
t.Logf("[DEBUG] Testing %q", v.Input)

actual, err := MicrosoftPartnerAccountBillingScopeID(v.Input)
if err != nil {
if v.Error {
continue
}

t.Fatalf("Expect a value but got an error: %s", err)
}
if v.Error {
t.Fatal("Expect an error but didn't get one")
}

if actual.BillingAccountName != v.Expected.BillingAccountName {
t.Fatalf("Expected %q but got %q for BillingAccountName", v.Expected.BillingAccountName, actual.BillingAccountName)
}
if actual.CustomerName != v.Expected.CustomerName {
t.Fatalf("Expected %q but got %q for CustomerName", v.Expected.CustomerName, actual.CustomerName)
}
}
}
1 change: 1 addition & 0 deletions internal/services/billing/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func (r Registration) SupportedDataSources() map[string]*pluginsdk.Resource {
return map[string]*pluginsdk.Resource{
"azurerm_billing_enrollment_account_scope": dataSourceBillingEnrollmentAccountScope(),
"azurerm_billing_mca_account_scope": dataSourceBillingMCAAccountScope(),
"azurerm_billing_mpa_account_scope": dataSourceBillingMPAAccountScope(),
}
}

Expand Down
21 changes: 21 additions & 0 deletions internal/services/billing/validate/mpa_billing_scope_id.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package validate

import (
"fmt"

"github.com/hashicorp/terraform-provider-azurerm/internal/services/billing/parse"
)

func MicrosoftPartnerAccountBillingScopeID(input interface{}, key string) (warnings []string, errors []error) {
v, ok := input.(string)
if !ok {
errors = append(errors, fmt.Errorf("expected %q to be a string", key))
return
}

if _, err := parse.MicrosoftPartnerAccountBillingScopeID(v); err != nil {
errors = append(errors, err)
}

return
}
62 changes: 62 additions & 0 deletions internal/services/billing/validate/mpa_billing_scope_id_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package validate

import "testing"

func TestMicrosoftPartnerAccountBillingScopeID(t *testing.T) {
cases := []struct {
Input string
Valid bool
}{

{
// empty
Input: "",
Valid: false,
},

{
// missing BillingAccountName
Input: "/providers/Microsoft.Billing/",
Valid: false,
},

{
// missing value for BillingAccountName
Input: "/providers/Microsoft.Billing/billingAccounts/",
Valid: false,
},

{
// missing CustomerName
Input: "/providers/Microsoft.Billing/billingAccounts/e879cf0f-2b4d-5431-109a-f72fc9868693:024cabf4-7321-4cf9-be59-df0c77ca51de_2019-05-31/",
Valid: false,
},

{
// missing value for CustomerName
Input: "/providers/Microsoft.Billing/billingAccounts/e879cf0f-2b4d-5431-109a-f72fc9868693:024cabf4-7321-4cf9-be59-df0c77ca51de_2019-05-31/customers/",
Valid: false,
},

{
// valid
Input: "/providers/Microsoft.Billing/billingAccounts/e879cf0f-2b4d-5431-109a-f72fc9868693:024cabf4-7321-4cf9-be59-df0c77ca51de_2019-05-31/customers/2281f543-7321-4cf9-1e23-edb4Oc31a31c",
Valid: true,
},

{
// upper-cased
Input: "/PROVIDERS/MICROSOFT.BILLING/BILLINGACCOUNTS/E879CF0F-2B4D-5431-109A-F72FC9868693:024CABF4-7321-4CF9-BE59-DF0C77CA51DE_2019-05-31/CUSTOMERS/2281F543-7321-4CF9-1E23-EDB4OC31A31C",
Valid: false,
},
}
for _, tc := range cases {
t.Logf("[DEBUG] Testing Value %s", tc.Input)
_, errors := MicrosoftPartnerAccountBillingScopeID(tc.Input, "test")
valid := len(errors) == 0

if tc.Valid != valid {
t.Fatalf("Expected %t but got %t", tc.Valid, valid)
}
}
}
1 change: 1 addition & 0 deletions internal/services/subscription/subscription_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ func resourceSubscription() *pluginsdk.Resource {
ValidateFunc: validation.Any(
billingValidate.MicrosoftCustomerAccountBillingScopeID,
billingValidate.EnrollmentBillingScopeID,
billingValidate.MicrosoftPartnerAccountBillingScopeID,
),
},

Expand Down
44 changes: 44 additions & 0 deletions website/docs/d/billing_mpa_account_scope.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
subcategory: "Billing"
layout: "azurerm"
page_title: "Azure Resource Manager: Data Source: azurerm_billing_mpa_account_scope"
description: |-
This is a helper Data Source to provide a correctly formatted Billing Scope ID for a Microsoft Partner Agreement Account.
---

# Data Source: azurerm_billing_mpa_account_scope

Use this data source to access an ID for your MPA Account billing scope.

## Example Usage

```hcl
data "azurerm_billing_mpa_account_scope" "example" {
billing_account_name = "e879cf0f-2b4d-5431-109a-f72fc9868693:024cabf4-7321-4cf9-be59-df0c77ca51de_2019-05-31"
customer_name = "2281f543-7321-4cf9-1e23-edb4Oc31a31c"
}

output "id" {
value = data.azurerm_billing_mpa_account_scope.example.id
}
```

## Arguments Reference

The following arguments are supported:

* `billing_account_name` - (Required) The Billing Account Name of the MPA account.

* `customer_name` - (Required) The Customer Name in the above Billing Account.

## Attributes Reference

In addition to the Arguments listed above - the following Attributes are exported:

* `id` - The ID of the Billing Scope.

## Timeouts

The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions:

* `read` - (Defaults to 5 minutes) Used when retrieving the Billing Scope.
Loading