From 19ad4f11faca6e2aedd7a77f310480fe216294ea Mon Sep 17 00:00:00 2001 From: JT <100274846+jiaweitao001@users.noreply.github.com> Date: Tue, 13 Aug 2024 21:25:26 +0800 Subject: [PATCH] New Resource: `azurerm_extended_location_custom_location` (#24267) * temp * acc test * extended location temp * Fix test * Update acc test * Update extension type * update test ext * New Resource: azurerm_extended_location_custom_location * update allowed cats * fix gencheck issue * Update to use commonschema * address some comments * update docs * pass golint * update to avoid nil dereference * temp * acc test * extended location temp * Fix test * Update acc test * Update extension type * update test ext * New Resource: azurerm_extended_location_custom_location * fix conflict * Added validation func, more acc test, updated script and docs * change name validation func * remove location overrride in acc tests * Address comments, remove unused location overrides, add examples in doc * Fix indent in client list * address comments, change elem type, removing redundant code * Update vendors * update oid in python script, add more comments inline for users * Address comments, remove some unupdatable attributes * revert * address comments on update --------- Co-authored-by: Elena Xin (Centific Technologies Inc) --- .github/labeler-issue-triage.yml | 3 + .github/labeler-pull-request-triage.yml | 5 + .teamcity/components/generated/services.kt | 1 + internal/clients/client.go | 5 + internal/provider/services.go | 2 + .../extendedlocation/client/client.go | 27 ++ .../extended_location_custom_location.go | 311 +++++++++++++++ .../extended_location_custom_location_test.go | 370 ++++++++++++++++++ .../services/extendedlocation/registration.go | 34 ++ .../testdata/install_agent.py | 256 ++++++++++++ .../testdata/install_agent.sh.tftpl | 38 ++ .../extendedlocation/testdata/kind.yaml | 20 + .../2021-10-01/connectedclusters/README.md | 142 +++++++ .../2021-10-01/connectedclusters/client.go | 26 ++ .../2021-10-01/connectedclusters/constants.go | 154 ++++++++ .../connectedclusters/id_connectedcluster.go | 130 ++++++ .../method_connectedclustercreate.go | 75 ++++ .../method_connectedclusterdelete.go | 71 ++++ .../method_connectedclusterget.go | 54 +++ ...hod_connectedclusterlistbyresourcegroup.go | 106 +++++ ...thod_connectedclusterlistbysubscription.go | 106 +++++ ...nnectedclusterlistclusterusercredential.go | 59 +++ .../method_connectedclusterupdate.go | 58 +++ .../model_connectedcluster.go | 20 + .../model_connectedclusterpatch.go | 9 + .../model_connectedclusterproperties.go | 49 +++ .../model_credentialresult.go | 9 + .../model_credentialresults.go | 9 + .../model_hybridconnectionconfig.go | 11 + ...del_listclusterusercredentialproperties.go | 9 + .../connectedclusters/predicates.go | 32 ++ .../2021-10-01/connectedclusters/version.go | 12 + vendor/modules.txt | 1 + website/allowed-subcategories | 1 + ...ded_location_custom_location.html.markdown | 138 +++++++ 35 files changed, 2353 insertions(+) create mode 100644 internal/services/extendedlocation/client/client.go create mode 100644 internal/services/extendedlocation/extended_location_custom_location.go create mode 100644 internal/services/extendedlocation/extended_location_custom_location_test.go create mode 100644 internal/services/extendedlocation/registration.go create mode 100644 internal/services/extendedlocation/testdata/install_agent.py create mode 100644 internal/services/extendedlocation/testdata/install_agent.sh.tftpl create mode 100644 internal/services/extendedlocation/testdata/kind.yaml create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/README.md create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/client.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/constants.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/id_connectedcluster.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclustercreate.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclusterdelete.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclusterget.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclusterlistbyresourcegroup.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclusterlistbysubscription.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclusterlistclusterusercredential.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclusterupdate.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_connectedcluster.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_connectedclusterpatch.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_connectedclusterproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_credentialresult.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_credentialresults.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_hybridconnectionconfig.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_listclusterusercredentialproperties.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/predicates.go create mode 100644 vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/version.go create mode 100644 website/docs/r/extended_location_custom_location.html.markdown diff --git a/.github/labeler-issue-triage.yml b/.github/labeler-issue-triage.yml index 49706a2acac5..305c541db4b8 100644 --- a/.github/labeler-issue-triage.yml +++ b/.github/labeler-issue-triage.yml @@ -141,6 +141,9 @@ service/event-grid: service/event-hubs: - '### (|New or )Affected Resource\(s\)\/Data Source\(s\)((.|\n)*)azurerm_eventhub((.|\n)*)###' +service/extended-location: + - '### (|New or )Affected Resource\(s\)\/Data Source\(s\)((.|\n)*)azurerm_extended_custom_location((.|\n)*)###' + service/firewall: - '### (|New or )Affected Resource\(s\)\/Data Source\(s\)((.|\n)*)azurerm_firewall((.|\n)*)###' diff --git a/.github/labeler-pull-request-triage.yml b/.github/labeler-pull-request-triage.yml index 1f21c88b7000..6f18bc1c2f61 100644 --- a/.github/labeler-pull-request-triage.yml +++ b/.github/labeler-pull-request-triage.yml @@ -239,6 +239,11 @@ service/event-hubs: - any-glob-to-any-file: - internal/services/eventhub/**/* +service/extended-location: +- changed-files: + - any-glob-to-any-file: + - internal/services/extendedlocation/**/* + service/firewall: - changed-files: - any-glob-to-any-file: diff --git a/.teamcity/components/generated/services.kt b/.teamcity/components/generated/services.kt index 78c055e88b34..7ccb89121910 100644 --- a/.teamcity/components/generated/services.kt +++ b/.teamcity/components/generated/services.kt @@ -53,6 +53,7 @@ var services = mapOf( "elasticsan" to "ElasticSan", "eventgrid" to "EventGrid", "eventhub" to "EventHub", + "extendedlocation" to "ExtendedLocation", "firewall" to "Firewall", "fluidrelay" to "Fluid Relay", "frontdoor" to "FrontDoor", diff --git a/internal/clients/client.go b/internal/clients/client.go index 131609fc3b72..5abe26789c57 100644 --- a/internal/clients/client.go +++ b/internal/clients/client.go @@ -73,6 +73,7 @@ import ( elasticsan "github.com/hashicorp/terraform-provider-azurerm/internal/services/elasticsan/client" eventgrid "github.com/hashicorp/terraform-provider-azurerm/internal/services/eventgrid/client" eventhub "github.com/hashicorp/terraform-provider-azurerm/internal/services/eventhub/client" + extendedlocation "github.com/hashicorp/terraform-provider-azurerm/internal/services/extendedlocation/client" fluidrelay "github.com/hashicorp/terraform-provider-azurerm/internal/services/fluidrelay/client" frontdoor "github.com/hashicorp/terraform-provider-azurerm/internal/services/frontdoor/client" graph "github.com/hashicorp/terraform-provider-azurerm/internal/services/graphservices/client" @@ -210,6 +211,7 @@ type Client struct { ElasticSan *elasticsan.Client EventGrid *eventgrid_v2022_06_15.Client Eventhub *eventhub.Client + ExtendedLocation *extendedlocation.Client FluidRelay *fluidrelay_2022_05_26.Client Frontdoor *frontdoor.Client Graph *graph.Client @@ -447,6 +449,9 @@ func (client *Client) Build(ctx context.Context, o *common.ClientOptions) error if client.Eventhub, err = eventhub.NewClient(o); err != nil { return fmt.Errorf("building clients for Eventhub: %+v", err) } + if client.ExtendedLocation, err = extendedlocation.NewClient(o); err != nil { + return fmt.Errorf("building clients for ExtendedLocation: %+v", err) + } if client.FluidRelay, err = fluidrelay.NewClient(o); err != nil { return fmt.Errorf("building clients for FluidRelay: %+v", err) } diff --git a/internal/provider/services.go b/internal/provider/services.go index 4505a786a387..fcb3b3ce04b9 100644 --- a/internal/provider/services.go +++ b/internal/provider/services.go @@ -53,6 +53,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/services/elasticsan" "github.com/hashicorp/terraform-provider-azurerm/internal/services/eventgrid" "github.com/hashicorp/terraform-provider-azurerm/internal/services/eventhub" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/extendedlocation" "github.com/hashicorp/terraform-provider-azurerm/internal/services/firewall" "github.com/hashicorp/terraform-provider-azurerm/internal/services/fluidrelay" "github.com/hashicorp/terraform-provider-azurerm/internal/services/frontdoor" @@ -171,6 +172,7 @@ func SupportedTypedServices() []sdk.TypedServiceRegistration { domainservices.Registration{}, elasticsan.Registration{}, eventhub.Registration{}, + extendedlocation.Registration{}, fluidrelay.Registration{}, graphservices.Registration{}, hybridcompute.Registration{}, diff --git a/internal/services/extendedlocation/client/client.go b/internal/services/extendedlocation/client/client.go new file mode 100644 index 000000000000..a6ecdda41e33 --- /dev/null +++ b/internal/services/extendedlocation/client/client.go @@ -0,0 +1,27 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package client + +import ( + "fmt" + + "github.com/hashicorp/go-azure-sdk/resource-manager/extendedlocation/2021-08-15/customlocations" + "github.com/hashicorp/terraform-provider-azurerm/internal/common" +) + +type Client struct { + CustomLocationsClient *customlocations.CustomLocationsClient +} + +func NewClient(o *common.ClientOptions) (*Client, error) { + customLocationsClient, err := customlocations.NewCustomLocationsClientWithBaseURI(o.Environment.ResourceManager) + if err != nil { + return nil, fmt.Errorf("building CustomLocations client: %+v", err) + } + o.Configure(customLocationsClient.Client, o.Authorizers.ResourceManager) + + return &Client{ + CustomLocationsClient: customLocationsClient, + }, nil +} diff --git a/internal/services/extendedlocation/extended_location_custom_location.go b/internal/services/extendedlocation/extended_location_custom_location.go new file mode 100644 index 000000000000..cb3bfbb38cd6 --- /dev/null +++ b/internal/services/extendedlocation/extended_location_custom_location.go @@ -0,0 +1,311 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package extendedlocation + +import ( + "context" + "fmt" + "regexp" + "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-sdk/resource-manager/extendedlocation/2021-08-15/customlocations" + arckubernetes "github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters" + "github.com/hashicorp/go-azure-sdk/resource-manager/kubernetesconfiguration/2022-11-01/extensions" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "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 CustomLocationResource struct{} + +type CustomLocationResourceModel struct { + Name string `tfschema:"name"` + ResourceGroupName string `tfschema:"resource_group_name"` + Location string `tfschema:"location"` + Authentication []AuthModel `tfschema:"authentication"` + ClusterExtensionIds []string `tfschema:"cluster_extension_ids"` + DisplayName string `tfschema:"display_name"` + HostResourceId string `tfschema:"host_resource_id"` + HostType string `tfschema:"host_type"` + Namespace string `tfschema:"namespace"` +} + +type AuthModel struct { + Type string `tfschema:"type"` + Value string `tfschema:"value"` +} + +func (r CustomLocationResource) Arguments() map[string]*pluginsdk.Schema { + return map[string]*schema.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringMatch( + regexp.MustCompile(`^[A-Za-z\d.\-_]*[A-Za-z\d]$`), + "supported alphanumeric characters and periods, underscores, hyphens. Name should end with an alphanumeric character.", + ), + }, + + "resource_group_name": commonschema.ResourceGroupName(), + + "location": commonschema.Location(), + + "namespace": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringMatch( + regexp.MustCompile("^[a-zA-Z0-9][a-zA-Z0-9-.]{0,252}$"), + "namespace must be between 1 and 253 characters in length and may contain only letters, numbers, periods (.), hyphens (-), and must begin with a letter or number.", + ), + }, + + "host_resource_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: arckubernetes.ValidateConnectedClusterID, + }, + + "cluster_extension_ids": { + Type: pluginsdk.TypeList, + Required: true, + Elem: commonschema.ResourceIDReferenceElem(&extensions.ScopedExtensionId{}), + }, + + "host_type": { + Type: pluginsdk.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + string(customlocations.HostTypeKubernetes), + }, false), + }, + + "display_name": { + Type: pluginsdk.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "authentication": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "type": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "value": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsBase64, + }, + }, + }, + }, + } +} + +func (r CustomLocationResource) Attributes() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{} +} + +func (r CustomLocationResource) ModelObject() interface{} { + return &CustomLocationResourceModel{} +} + +func (r CustomLocationResource) ResourceType() string { + return "azurerm_extended_custom_location" +} + +func (r CustomLocationResource) Create() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + var model CustomLocationResourceModel + if err := metadata.Decode(&model); err != nil { + return err + } + + subscriptionId := metadata.Client.Account.SubscriptionId + client := metadata.Client.ExtendedLocation.CustomLocationsClient + + id := customlocations.NewCustomLocationID(subscriptionId, model.ResourceGroupName, model.Name) + existing, err := client.Get(ctx, id) + if err != nil && !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for presence of existing %s: %+v", id, err) + } + + if !response.WasNotFound(existing.HttpResponse) { + return metadata.ResourceRequiresImport(r.ResourceType(), id) + } + + customLocationProps := customlocations.CustomLocationProperties{ + ClusterExtensionIds: pointer.To(model.ClusterExtensionIds), + DisplayName: pointer.To(model.DisplayName), + HostResourceId: pointer.To(model.HostResourceId), + HostType: pointer.To(customlocations.HostType(model.HostType)), + Namespace: pointer.To(model.Namespace), + } + + if len(model.Authentication) > 0 { + auth := model.Authentication[0] + customLocationProps.Authentication = &customlocations.CustomLocationPropertiesAuthentication{ + Type: pointer.To(auth.Type), + Value: pointer.To(auth.Value), + } + } + + props := customlocations.CustomLocation{ + Id: pointer.To(id.ID()), + Location: model.Location, + Name: pointer.To(model.Name), + Properties: pointer.To(customLocationProps), + } + + if err := client.CreateOrUpdateThenPoll(ctx, id, props); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + metadata.SetID(id) + return nil + }, + } +} + +func (r CustomLocationResource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.ExtendedLocation.CustomLocationsClient + id, err := customlocations.ParseCustomLocationID(metadata.ResourceData.Id()) + 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("reading %s: %+v", *id, err) + } + + if model := resp.Model; model != nil { + props := model.Properties + + state := CustomLocationResourceModel{ + Name: id.CustomLocationName, + ResourceGroupName: id.ResourceGroupName, + Location: model.Location, + ClusterExtensionIds: pointer.From(props.ClusterExtensionIds), + DisplayName: pointer.From(props.DisplayName), + HostResourceId: pointer.From(props.HostResourceId), + HostType: string(pointer.From(props.HostType)), + Namespace: pointer.From(props.Namespace), + } + + // API always returns an empty `authentication` block even it's not specified. Tracing the bug: https://github.com/Azure/azure-rest-api-specs/issues/30101 + if props.Authentication != nil && props.Authentication.Type != nil && props.Authentication.Value != nil { + state.Authentication = []AuthModel{ + { + Type: pointer.From(props.Authentication.Type), + Value: pointer.From(props.Authentication.Value), + }, + } + } + + return metadata.Encode(&state) + } + return nil + }, + } +} + +func (r CustomLocationResource) Delete() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.ExtendedLocation.CustomLocationsClient + id, err := customlocations.ParseCustomLocationID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + metadata.Logger.Infof("deleting %s", *id) + + if err := client.DeleteThenPoll(ctx, *id); err != nil { + return fmt.Errorf("deleting %s: %+v", id, err) + } + + return nil + }, + } +} + +func (r CustomLocationResource) Update() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.ExtendedLocation.CustomLocationsClient + id, err := customlocations.ParseCustomLocationID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + var state CustomLocationResourceModel + if err := metadata.Decode(&state); err != nil { + return fmt.Errorf("decoding %+v", err) + } + + existing, err := client.Get(ctx, *id) + if err != nil { + return err + } + + model := existing.Model + + if model.Properties == nil { + return fmt.Errorf("retreiving properties for %s for update: %+v", *id, err) + } + d := metadata.ResourceData + + if d.HasChanges("authentication") { + if len(state.Authentication) > 0 { + auth := state.Authentication[0] + model.Properties.Authentication = &customlocations.CustomLocationPropertiesAuthentication{ + Type: pointer.To(auth.Type), + Value: pointer.To(auth.Value), + } + } + } else { + model.Properties.Authentication = nil + } + + if d.HasChange("cluster_extension_ids") { + model.Properties.ClusterExtensionIds = pointer.To(state.ClusterExtensionIds) + } + + if _, err := client.CreateOrUpdate(ctx, *id, *model); err != nil { + return fmt.Errorf("updating %s: %+v", *id, err) + } + return nil + }, + } +} + +func (r CustomLocationResource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return customlocations.ValidateCustomLocationID +} diff --git a/internal/services/extendedlocation/extended_location_custom_location_test.go b/internal/services/extendedlocation/extended_location_custom_location_test.go new file mode 100644 index 000000000000..740df1db9bdd --- /dev/null +++ b/internal/services/extendedlocation/extended_location_custom_location_test.go @@ -0,0 +1,370 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package extendedlocation_test + +import ( + "context" + cryptoRand "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "fmt" + "math/rand" + "testing" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/extendedlocation/2021-08-15/customlocations" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type CustomLocationResource struct{} + +func (r CustomLocationResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := customlocations.ParseCustomLocationID(state.ID) + if err != nil { + return nil, err + } + + resp, err := client.ExtendedLocation.CustomLocationsClient.Get(ctx, *id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return utils.Bool(false), nil + } + return nil, fmt.Errorf("retrieving %s: %+v", *id, err) + } + return utils.Bool(true), nil +} + +func TestAccExtendedLocationCustomLocations_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_extended_custom_location", "test") + r := CustomLocationResource{} + credential, privateKey, publicKey := r.getCredentials(t) + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data, credential, privateKey, publicKey), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccExtendedLocationCustomLocations_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_extended_custom_location", "test") + r := CustomLocationResource{} + credential, privateKey, publicKey := r.getCredentials(t) + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data, credential, privateKey, publicKey), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccExtendedLocationCustomLocations_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_extended_custom_location", "test") + r := CustomLocationResource{} + credential, privateKey, publicKey := r.getCredentials(t) + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data, credential, privateKey, publicKey), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.update(data, credential, privateKey, publicKey), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func (r CustomLocationResource) basic(data acceptance.TestData, credential string, privateKey string, publicKey string) string { + template := r.template(data, credential, publicKey, privateKey) + return fmt.Sprintf(` +%s + +resource "azurerm_extended_custom_location" "test" { + name = "acctestcustomlocation%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + cluster_extension_ids = [ + azurerm_arc_kubernetes_cluster_extension.test.id + ] + namespace = "namespace%[2]d" + host_resource_id = azurerm_arc_kubernetes_cluster.test.id +} +`, template, data.RandomInteger) +} + +func (r CustomLocationResource) update(data acceptance.TestData, credential string, privateKey string, publicKey string) string { + template := r.template(data, credential, publicKey, privateKey) + return fmt.Sprintf(` +%s + +resource "azurerm_extended_custom_location" "test" { + name = "acctestcustomlocation%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + cluster_extension_ids = [ + azurerm_arc_kubernetes_cluster_extension.test.id + ] + + display_name = "customlocationupdate%[2]d" + namespace = "namespace%[2]d" + host_resource_id = azurerm_arc_kubernetes_cluster.test.id +} +`, template, data.RandomInteger) +} + +func (r CustomLocationResource) complete(data acceptance.TestData, credential string, privateKey string, publicKey string) string { + template := r.template(data, credential, publicKey, privateKey) + return fmt.Sprintf(` +%s + +resource "azurerm_extended_custom_location" "test" { + name = "acctestcustomlocation%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + host_type = "Kubernetes" + cluster_extension_ids = [ + azurerm_arc_kubernetes_cluster_extension.test.id + ] + display_name = "customlocationcomplete%[2]d" + namespace = "namespace%[2]d" + host_resource_id = azurerm_arc_kubernetes_cluster.test.id +} +`, template, data.RandomInteger) +} + +func (r CustomLocationResource) template(data acceptance.TestData, credential string, publicKey string, privateKey string) string { + provisionTemplate := r.provisionTemplate(data, credential, privateKey) + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +data "azurerm_client_config" "current" {} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%[1]d" + location = "%[2]s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctestnw-%[1]d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test" { + name = "internal" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] +} + +resource "azurerm_public_ip" "test" { + name = "acctestpip-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + allocation_method = "Static" +} + +resource "azurerm_network_interface" "test" { + name = "acctestnic-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + ip_configuration { + name = "internal" + subnet_id = azurerm_subnet.test.id + private_ip_address_allocation = "Dynamic" + public_ip_address_id = azurerm_public_ip.test.id + } +} + +resource "azurerm_network_security_group" "my_terraform_nsg" { + name = "myNetworkSG-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + security_rule { + name = "SSH" + priority = 1001 + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_range = "*" + destination_port_range = "22" + source_address_prefix = "*" + destination_address_prefix = "*" + } + + lifecycle { + ignore_changes = [ + security_rule, + ] + } +} + +resource "azurerm_network_interface_security_group_association" "test" { + network_interface_id = azurerm_network_interface.test.id + network_security_group_id = azurerm_network_security_group.my_terraform_nsg.id +} + +resource "azurerm_linux_virtual_machine" "test" { + name = "acctestVM-%[1]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + size = "Standard_F2" + admin_username = "adminuser" + admin_password = "%[3]s" + provision_vm_agent = false + allow_extension_operations = false + disable_password_authentication = false + network_interface_ids = [ + azurerm_network_interface.test.id, + ] + os_disk { + caching = "ReadWrite" + storage_account_type = "Standard_LRS" + } + source_image_reference { + publisher = "Canonical" + offer = "0001-com-ubuntu-server-jammy" + sku = "22_04-lts" + version = "latest" + } + + depends_on = [ + azurerm_network_interface_security_group_association.test + ] +} + +resource "azurerm_arc_kubernetes_cluster" "test" { + name = "acctest-akcc-%[1]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + agent_public_key_certificate = "%[4]s" + identity { + type = "SystemAssigned" + } + + %[5]s + + depends_on = [ + azurerm_linux_virtual_machine.test + ] +} + +resource "azurerm_arc_kubernetes_cluster_extension" "test" { + name = "extension-%[1]d" + cluster_id = azurerm_arc_kubernetes_cluster.test.id + extension_type = "microsoft.vmware" + release_namespace = "vmware-extension" + + configuration_settings = { + "Microsoft.CustomLocation.ServiceAccount" = "vmware-operator" + } + + identity { + type = "SystemAssigned" + } +} +`, data.RandomInteger, data.Locations.Primary, credential, publicKey, provisionTemplate) +} + +func (r CustomLocationResource) generateKey() (string, string, error) { + privateKey, err := rsa.GenerateKey(cryptoRand.Reader, 4096) + if err != nil { + return "", "", fmt.Errorf("failed to generate RSA key") + } + + privateKeyBytes := x509.MarshalPKCS1PrivateKey(privateKey) + privateKeyBlock := &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: privateKeyBytes, + } + + privatePem := pem.EncodeToMemory(privateKeyBlock) + if privatePem == nil { + return "", "", fmt.Errorf("failed to encode pem") + } + + return string(privatePem), base64.StdEncoding.EncodeToString(x509.MarshalPKCS1PublicKey(&privateKey.PublicKey)), nil +} + +func (r CustomLocationResource) getCredentials(t *testing.T) (credential, privateKey, publicKey string) { + credential = fmt.Sprintf("P@$$w0rd%d!", rand.Intn(10000)) + privateKey, publicKey, err := r.generateKey() + if err != nil { + t.Fatalf("failed to generate key: %+v", err) + } + + return +} + +func (r CustomLocationResource) provisionTemplate(data acceptance.TestData, credential string, privateKey string) string { + return fmt.Sprintf(` +connection { + type = "ssh" + host = azurerm_public_ip.test.ip_address + user = "adminuser" + password = "%[1]s" +} + +provisioner "file" { + content = templatefile("testdata/install_agent.sh.tftpl", { + subscription_id = data.azurerm_client_config.current.subscription_id + resource_group_name = azurerm_resource_group.test.name + cluster_name = "acctest-akcc-%[2]d" + location = azurerm_resource_group.test.location + tenant_id = data.azurerm_client_config.current.tenant_id + working_dir = "%[3]s" + }) + destination = "%[3]s/install_agent.sh" +} + +provisioner "file" { + source = "testdata/install_agent.py" + destination = "%[3]s/install_agent.py" +} + +provisioner "file" { + source = "testdata/kind.yaml" + destination = "%[3]s/kind.yaml" +} + +provisioner "file" { + content = < %[3]s/agent_log", + ] +} +`, credential, data.RandomInteger, "/home/adminuser", privateKey) +} diff --git a/internal/services/extendedlocation/registration.go b/internal/services/extendedlocation/registration.go new file mode 100644 index 000000000000..a0e8b63dab4b --- /dev/null +++ b/internal/services/extendedlocation/registration.go @@ -0,0 +1,34 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package extendedlocation + +import "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" + +type Registration struct{} + +var _ sdk.TypedServiceRegistration = Registration{} + +func (r Registration) AssociatedGitHubLabel() string { + return "service/extended-location" +} + +func (r Registration) WebsiteCategories() []string { + return []string{ + "Extended Location", + } +} + +func (r Registration) DataSources() []sdk.DataSource { + return []sdk.DataSource{} +} + +func (r Registration) Resources() []sdk.Resource { + return []sdk.Resource{ + CustomLocationResource{}, + } +} + +func (r Registration) Name() string { + return "ExtendedLocation" +} diff --git a/internal/services/extendedlocation/testdata/install_agent.py b/internal/services/extendedlocation/testdata/install_agent.py new file mode 100644 index 000000000000..a1640c942dc1 --- /dev/null +++ b/internal/services/extendedlocation/testdata/install_agent.py @@ -0,0 +1,256 @@ +# This python script is used to install a Helm client on the cluster. +# This should be identical to the script used in the Azure Arc onboarding flow, plus setting custom location enabled. + +import argparse +import json +import logging as logger +import os +import platform +import shutil +import stat +import subprocess +import time +import urllib +from subprocess import PIPE, Popen +from urllib import request + +HELM_VERSION = 'v3.6.3' +HELM_STORAGE_URL = "https://k8connecthelm.azureedge.net" +Pre_Onboarding_Helm_Charts_Folder_Name = 'PreOnboardingChecksCharts' + + +def get_helm_registry(config_dp_endpoint): + # Setting uri + get_chart_location_url = "{}/{}/GetLatestHelmPackagePath?api-version=2019-11-01-preview".format( + config_dp_endpoint, 'azure-arc-k8sagents') + + try: + response = urllib.request.urlopen( + request.Request(get_chart_location_url, method="POST")) + except Exception as e: + raise Exception("Failed to get helm registry." + str(e)) + + try: + return json.load(response).get('repositoryPath') + except Exception as e: + raise Exception( + "Error while fetching helm chart registry path from JSON response: " + str(e)) + + +def pull_helm_chart(registry_path, kube_config, kube_context, helm_client_location, chart_name='azure-arc-k8sagents', retry_count=5, retry_delay=3): + cmd_helm_chart_pull = [helm_client_location, + "chart", "pull", registry_path] + if kube_config: + cmd_helm_chart_pull.extend(["--kubeconfig", kube_config]) + if kube_context: + cmd_helm_chart_pull.extend(["--kube-context", kube_context]) + for i in range(retry_count): + response_helm_chart_pull = subprocess.Popen( + cmd_helm_chart_pull, stdout=PIPE, stderr=PIPE) + _, error_helm_chart_pull = response_helm_chart_pull.communicate() + if response_helm_chart_pull.returncode != 0: + if i == retry_count - 1: + raise Exception("Unable to pull {} helm chart from the registry '{}': ".format( + chart_name, registry_path) + error_helm_chart_pull.decode("ascii")) + time.sleep(retry_delay) + else: + break + + +def export_helm_chart(registry_path, chart_export_path, kube_config, kube_context, helm_client_location, chart_name='azure-arc-k8sagents'): + cmd_helm_chart_export = [helm_client_location, "chart", + "export", registry_path, "--destination", chart_export_path] + if kube_config: + cmd_helm_chart_export.extend(["--kubeconfig", kube_config]) + if kube_context: + cmd_helm_chart_export.extend(["--kube-context", kube_context]) + response_helm_chart_export = subprocess.Popen( + cmd_helm_chart_export, stdout=PIPE, stderr=PIPE) + _, error_helm_chart_export = response_helm_chart_export.communicate() + if response_helm_chart_export.returncode != 0: + raise Exception("Unable to export {} helm chart from the registry '{}': ".format( + chart_name, registry_path) + error_helm_chart_export.decode("ascii")) + + +def get_chart_path(registry_path, kube_config, kube_context, helm_client_location, chart_folder_name='AzureArcCharts', chart_name='azure-arc-k8sagents'): + # Pulling helm chart from registry + os.environ['HELM_EXPERIMENTAL_OCI'] = '1' + pull_helm_chart(registry_path, kube_config, kube_context, + helm_client_location, chart_name) + + # Exporting helm chart after cleanup + chart_export_path = os.path.join( + os.path.expanduser('~'), '.azure', chart_folder_name) + try: + if os.path.isdir(chart_export_path): + shutil.rmtree(chart_export_path) + except: + logger.warning("Unable to cleanup the {} already present on the machine. In case of failure, please cleanup the directory '{}' and try again.".format( + chart_folder_name, chart_export_path)) + + export_helm_chart(registry_path, chart_export_path, kube_config, + kube_context, helm_client_location, chart_name) + + # Returning helm chart path + helm_chart_path = os.path.join(chart_export_path, chart_name) + if chart_folder_name == Pre_Onboarding_Helm_Charts_Folder_Name: + chart_path = helm_chart_path + else: + chart_path = os.getenv('HELMCHART') if os.getenv( + 'HELMCHART') else helm_chart_path + + return chart_path + + +def install_helm_client(): + # Fetch system related info + operating_system = platform.system().lower() + platform.machine() + + # Set helm binary download & install locations + if (operating_system == 'windows'): + download_location_string = f'.azure\\helm\\{HELM_VERSION}\\helm-{HELM_VERSION}-{operating_system}-amd64.zip' + install_location_string = f'.azure\\helm\\{HELM_VERSION}\\{operating_system}-amd64\\helm.exe' + requestUri = f'{HELM_STORAGE_URL}/helm/helm-{HELM_VERSION}-{operating_system}-amd64.zip' + elif (operating_system == 'linux' or operating_system == 'darwin'): + download_location_string = f'.azure/helm/{HELM_VERSION}/helm-{HELM_VERSION}-{operating_system}-amd64.tar.gz' + install_location_string = f'.azure/helm/{HELM_VERSION}/{operating_system}-amd64/helm' + requestUri = f'{HELM_STORAGE_URL}/helm/helm-{HELM_VERSION}-{operating_system}-amd64.tar.gz' + else: + raise Exception( + f'The {operating_system} platform is not currently supported for installing helm client.') + + download_location = os.path.expanduser( + os.path.join('~', download_location_string)) + download_dir = os.path.dirname(download_location) + install_location = os.path.expanduser( + os.path.join('~', install_location_string)) + + # Download compressed halm binary if not already present + if not os.path.isfile(download_location): + # Creating the helm folder if it doesnt exist + if not os.path.exists(download_dir): + try: + os.makedirs(download_dir) + except Exception as e: + raise Exception("Failed to create helm directory." + str(e)) + + # Downloading compressed helm client executable + logger.warning( + "Downloading helm client for first time. This can take few minutes...") + try: + response = urllib.request.urlopen(requestUri) + except Exception as e: + raise Exception("Failed to download helm client." + str(e)) + + responseContent = response.read() + response.close() + + # Creating the compressed helm binaries + try: + with open(download_location, 'wb') as f: + f.write(responseContent) + except Exception as e: + raise Exception("Failed to create helm executable." + str(e)) + + # Extract compressed helm binary + if not os.path.isfile(install_location): + try: + shutil.unpack_archive(download_location, download_dir) + os.chmod(install_location, os.stat( + install_location).st_mode | stat.S_IXUSR) + except Exception as e: + raise Exception("Failed to extract helm executable." + str(e)) + + return install_location + + +def helm_install_release(chart_path, subscription_id, kubernetes_distro, kubernetes_infra, resource_group_name, cluster_name, + location, onboarding_tenant_id, private_key_pem, + no_wait, cloud_name, helm_client_location, onboarding_timeout="600"): + cmd_helm_install = [helm_client_location, "upgrade", "--install", "azure-arc", chart_path, + "--set", "global.subscriptionId={}".format( + subscription_id), + "--set", "global.kubernetesDistro={}".format( + kubernetes_distro), + "--set", "global.kubernetesInfra={}".format( + kubernetes_infra), + "--set", "global.resourceGroupName={}".format( + resource_group_name), + "--set", "global.resourceName={}".format(cluster_name), + "--set", "global.location={}".format(location), + "--set", "global.tenantId={}".format( + onboarding_tenant_id), + "--set", "global.onboardingPrivateKey={}".format( + private_key_pem), + "--set", "systemDefaultValues.spnOnboarding=false", + "--set", "global.azureEnvironment={}".format( + cloud_name), + "--set", "systemDefaultValues.clusterconnect-agent.enabled=true", + "--set", "systemDefaultValues.customLocations.enabled=true", + # ccce55cc-eb6c-45ec-b9ca-562ababa6a44 is from: az ad sp show --id bc313c14-388c-4e7d-a58e-70017303ee3b --query id -o tsv + # As a user, you need to run the above command to get the object id of the service principal and replace it in the below command. + # refs: https://learn.microsoft.com/en-us/azure/azure-arc/kubernetes/custom-locations#enable-custom-locations-on-your-cluster + "--set", "systemDefaultValues.customLocations.oid={}".format("ccce55cc-eb6c-45ec-b9ca-562ababa6a44"), + "--namespace", "{}".format("azure-arc-release"), + "--create-namespace", + "--output", "json"] + + if not no_wait: + # Change --timeout format for helm client to understand + onboarding_timeout = onboarding_timeout + "s" + cmd_helm_install.extend( + ["--wait", "--timeout", "{}".format(onboarding_timeout)]) + response_helm_install = Popen(cmd_helm_install, stdout=PIPE, stderr=PIPE) + _, error_helm_install = response_helm_install.communicate() + if response_helm_install.returncode != 0: + raise Exception("Unable to install helm release" + error_helm_install.decode("ascii")) + + +def install_agent(): + parser = argparse.ArgumentParser( + description='Install Connected Cluster Agent') + parser.add_argument('--subscriptionId', type=str, required=True) + parser.add_argument('--resourceGroupName', type=str, required=True) + parser.add_argument('--clusterName', type=str, required=True) + parser.add_argument('--location', type=str, required=True) + parser.add_argument('--tenantId', type=str, required=True) + parser.add_argument('--privatePem', type=str, required=True) + + try: + args = parser.parse_args() + except Exception as e: + raise Exception("Failed to parse arguments." + str(e)) + + try: + with open(args.privatePem, "r") as f: + privateKey = f.read() + except Exception as e: + raise Exception("Failed to get private key." + str(e)) + + # Install helm client + helm_client_location = install_helm_client() + + # Retrieving Helm chart OCI Artifact location + registry_path = get_helm_registry("https://westeurope.dp.kubernetesconfiguration.azure.com") + + # Get helm chart path + chart_path = get_chart_path( + registry_path, None, None, helm_client_location) + + helm_install_release(chart_path, + args.subscriptionId, + "generic", + "generic", + args.resourceGroupName, + args.clusterName, + args.location, + args.tenantId, + privateKey, + False, + "AZUREPUBLICCLOUD", + helm_client_location) + + +if __name__ == "__main__": + install_agent() diff --git a/internal/services/extendedlocation/testdata/install_agent.sh.tftpl b/internal/services/extendedlocation/testdata/install_agent.sh.tftpl new file mode 100644 index 000000000000..29377367079f --- /dev/null +++ b/internal/services/extendedlocation/testdata/install_agent.sh.tftpl @@ -0,0 +1,38 @@ +#!/bin/bash + +# install docker +sudo apt-get update +sudo apt-get -y install ca-certificates curl gnupg lsb-release +sudo mkdir -m 0755 -p /etc/apt/keyrings +curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg +echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ + $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null +sudo chmod a+r /etc/apt/keyrings/docker.gpg +sudo apt-get update +sudo apt-get -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin + +#Manage Docker as a non-root user +sudo groupadd docker || true +sudo usermod -aG docker $USER +newgrp docker << END + +#install golang and kind +sudo snap install go --classic +go install sigs.k8s.io/kind@latest + +#create a new cluster +export PATH="$HOME/go/bin:$PATH" +export KUBECONFIG="${working_dir}/kind-config" +kind create cluster --name arc-kind --config kind.yaml --kubeconfig kind-config + +#install agent +python3 "${working_dir}/install_agent.py" \ +--subscriptionId "${subscription_id}" \ +--resourceGroupName "${resource_group_name}" \ +--clusterName "${cluster_name}" \ +--location "${location}" \ +--tenantId "${tenant_id}" \ +--privatePem "${working_dir}/private.pem" + +END \ No newline at end of file diff --git a/internal/services/extendedlocation/testdata/kind.yaml b/internal/services/extendedlocation/testdata/kind.yaml new file mode 100644 index 000000000000..9f5717060033 --- /dev/null +++ b/internal/services/extendedlocation/testdata/kind.yaml @@ -0,0 +1,20 @@ +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +nodes: +- role: control-plane + kubeadmConfigPatches: + - | + kind: InitConfiguration + nodeRegistration: + kubeletExtraArgs: + node-labels: "ingress-ready=true" + # port forward 80 on the host to 80 on this node + extraPortMappings: + - containerPort: 81 + hostPort: 81 + listenAddress: "127.0.0.1" + protocol: TCP + - containerPort: 443 + hostPort: 443 + listenAddress: "127.0.0.1" + protocol: TCP diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/README.md b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/README.md new file mode 100644 index 000000000000..29736a828c95 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/README.md @@ -0,0 +1,142 @@ + +## `github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters` Documentation + +The `connectedclusters` SDK allows for interaction with the Azure Resource Manager Service `hybridkubernetes` (API Version `2021-10-01`). + +This readme covers example usages, but further information on [using this SDK can be found in the project root](https://github.com/hashicorp/go-azure-sdk/tree/main/docs). + +### Import Path + +```go +import "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" +import "github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters" +``` + + +### Client Initialization + +```go +client := connectedclusters.NewConnectedClustersClientWithBaseURI("https://management.azure.com") +client.Client.Authorizer = authorizer +``` + + +### Example Usage: `ConnectedClustersClient.ConnectedClusterCreate` + +```go +ctx := context.TODO() +id := connectedclusters.NewConnectedClusterID("12345678-1234-9876-4563-123456789012", "example-resource-group", "connectedClusterValue") + +payload := connectedclusters.ConnectedCluster{ + // ... +} + + +if err := client.ConnectedClusterCreateThenPoll(ctx, id, payload); err != nil { + // handle the error +} +``` + + +### Example Usage: `ConnectedClustersClient.ConnectedClusterDelete` + +```go +ctx := context.TODO() +id := connectedclusters.NewConnectedClusterID("12345678-1234-9876-4563-123456789012", "example-resource-group", "connectedClusterValue") + +if err := client.ConnectedClusterDeleteThenPoll(ctx, id); err != nil { + // handle the error +} +``` + + +### Example Usage: `ConnectedClustersClient.ConnectedClusterGet` + +```go +ctx := context.TODO() +id := connectedclusters.NewConnectedClusterID("12345678-1234-9876-4563-123456789012", "example-resource-group", "connectedClusterValue") + +read, err := client.ConnectedClusterGet(ctx, id) +if err != nil { + // handle the error +} +if model := read.Model; model != nil { + // do something with the model/response object +} +``` + + +### Example Usage: `ConnectedClustersClient.ConnectedClusterListByResourceGroup` + +```go +ctx := context.TODO() +id := commonids.NewResourceGroupID("12345678-1234-9876-4563-123456789012", "example-resource-group") + +// alternatively `client.ConnectedClusterListByResourceGroup(ctx, id)` can be used to do batched pagination +items, err := client.ConnectedClusterListByResourceGroupComplete(ctx, id) +if err != nil { + // handle the error +} +for _, item := range items { + // do something +} +``` + + +### Example Usage: `ConnectedClustersClient.ConnectedClusterListBySubscription` + +```go +ctx := context.TODO() +id := commonids.NewSubscriptionID("12345678-1234-9876-4563-123456789012") + +// alternatively `client.ConnectedClusterListBySubscription(ctx, id)` can be used to do batched pagination +items, err := client.ConnectedClusterListBySubscriptionComplete(ctx, id) +if err != nil { + // handle the error +} +for _, item := range items { + // do something +} +``` + + +### Example Usage: `ConnectedClustersClient.ConnectedClusterListClusterUserCredential` + +```go +ctx := context.TODO() +id := connectedclusters.NewConnectedClusterID("12345678-1234-9876-4563-123456789012", "example-resource-group", "connectedClusterValue") + +payload := connectedclusters.ListClusterUserCredentialProperties{ + // ... +} + + +read, err := client.ConnectedClusterListClusterUserCredential(ctx, id, payload) +if err != nil { + // handle the error +} +if model := read.Model; model != nil { + // do something with the model/response object +} +``` + + +### Example Usage: `ConnectedClustersClient.ConnectedClusterUpdate` + +```go +ctx := context.TODO() +id := connectedclusters.NewConnectedClusterID("12345678-1234-9876-4563-123456789012", "example-resource-group", "connectedClusterValue") + +payload := connectedclusters.ConnectedClusterPatch{ + // ... +} + + +read, err := client.ConnectedClusterUpdate(ctx, id, payload) +if err != nil { + // handle the error +} +if model := read.Model; model != nil { + // do something with the model/response object +} +``` diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/client.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/client.go new file mode 100644 index 000000000000..c25ebd209c77 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/client.go @@ -0,0 +1,26 @@ +package connectedclusters + +import ( + "fmt" + + "github.com/hashicorp/go-azure-sdk/sdk/client/resourcemanager" + sdkEnv "github.com/hashicorp/go-azure-sdk/sdk/environments" +) + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type ConnectedClustersClient struct { + Client *resourcemanager.Client +} + +func NewConnectedClustersClientWithBaseURI(sdkApi sdkEnv.Api) (*ConnectedClustersClient, error) { + client, err := resourcemanager.NewResourceManagerClient(sdkApi, "connectedclusters", defaultApiVersion) + if err != nil { + return nil, fmt.Errorf("instantiating ConnectedClustersClient: %+v", err) + } + + return &ConnectedClustersClient{ + Client: client, + }, nil +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/constants.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/constants.go new file mode 100644 index 000000000000..2cd96141a25a --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/constants.go @@ -0,0 +1,154 @@ +package connectedclusters + +import ( + "encoding/json" + "fmt" + "strings" +) + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type AuthenticationMethod string + +const ( + AuthenticationMethodAAD AuthenticationMethod = "AAD" + AuthenticationMethodToken AuthenticationMethod = "Token" +) + +func PossibleValuesForAuthenticationMethod() []string { + return []string{ + string(AuthenticationMethodAAD), + string(AuthenticationMethodToken), + } +} + +func (s *AuthenticationMethod) UnmarshalJSON(bytes []byte) error { + var decoded string + if err := json.Unmarshal(bytes, &decoded); err != nil { + return fmt.Errorf("unmarshaling: %+v", err) + } + out, err := parseAuthenticationMethod(decoded) + if err != nil { + return fmt.Errorf("parsing %q: %+v", decoded, err) + } + *s = *out + return nil +} + +func parseAuthenticationMethod(input string) (*AuthenticationMethod, error) { + vals := map[string]AuthenticationMethod{ + "aad": AuthenticationMethodAAD, + "token": AuthenticationMethodToken, + } + if v, ok := vals[strings.ToLower(input)]; ok { + return &v, nil + } + + // otherwise presume it's an undefined value and best-effort it + out := AuthenticationMethod(input) + return &out, nil +} + +type ConnectivityStatus string + +const ( + ConnectivityStatusConnected ConnectivityStatus = "Connected" + ConnectivityStatusConnecting ConnectivityStatus = "Connecting" + ConnectivityStatusExpired ConnectivityStatus = "Expired" + ConnectivityStatusOffline ConnectivityStatus = "Offline" +) + +func PossibleValuesForConnectivityStatus() []string { + return []string{ + string(ConnectivityStatusConnected), + string(ConnectivityStatusConnecting), + string(ConnectivityStatusExpired), + string(ConnectivityStatusOffline), + } +} + +func (s *ConnectivityStatus) UnmarshalJSON(bytes []byte) error { + var decoded string + if err := json.Unmarshal(bytes, &decoded); err != nil { + return fmt.Errorf("unmarshaling: %+v", err) + } + out, err := parseConnectivityStatus(decoded) + if err != nil { + return fmt.Errorf("parsing %q: %+v", decoded, err) + } + *s = *out + return nil +} + +func parseConnectivityStatus(input string) (*ConnectivityStatus, error) { + vals := map[string]ConnectivityStatus{ + "connected": ConnectivityStatusConnected, + "connecting": ConnectivityStatusConnecting, + "expired": ConnectivityStatusExpired, + "offline": ConnectivityStatusOffline, + } + if v, ok := vals[strings.ToLower(input)]; ok { + return &v, nil + } + + // otherwise presume it's an undefined value and best-effort it + out := ConnectivityStatus(input) + return &out, nil +} + +type ProvisioningState string + +const ( + ProvisioningStateAccepted ProvisioningState = "Accepted" + ProvisioningStateCanceled ProvisioningState = "Canceled" + ProvisioningStateDeleting ProvisioningState = "Deleting" + ProvisioningStateFailed ProvisioningState = "Failed" + ProvisioningStateProvisioning ProvisioningState = "Provisioning" + ProvisioningStateSucceeded ProvisioningState = "Succeeded" + ProvisioningStateUpdating ProvisioningState = "Updating" +) + +func PossibleValuesForProvisioningState() []string { + return []string{ + string(ProvisioningStateAccepted), + string(ProvisioningStateCanceled), + string(ProvisioningStateDeleting), + string(ProvisioningStateFailed), + string(ProvisioningStateProvisioning), + string(ProvisioningStateSucceeded), + string(ProvisioningStateUpdating), + } +} + +func (s *ProvisioningState) UnmarshalJSON(bytes []byte) error { + var decoded string + if err := json.Unmarshal(bytes, &decoded); err != nil { + return fmt.Errorf("unmarshaling: %+v", err) + } + out, err := parseProvisioningState(decoded) + if err != nil { + return fmt.Errorf("parsing %q: %+v", decoded, err) + } + *s = *out + return nil +} + +func parseProvisioningState(input string) (*ProvisioningState, error) { + vals := map[string]ProvisioningState{ + "accepted": ProvisioningStateAccepted, + "canceled": ProvisioningStateCanceled, + "deleting": ProvisioningStateDeleting, + "failed": ProvisioningStateFailed, + "provisioning": ProvisioningStateProvisioning, + "succeeded": ProvisioningStateSucceeded, + "updating": ProvisioningStateUpdating, + } + if v, ok := vals[strings.ToLower(input)]; ok { + return &v, nil + } + + // otherwise presume it's an undefined value and best-effort it + out := ProvisioningState(input) + return &out, nil +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/id_connectedcluster.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/id_connectedcluster.go new file mode 100644 index 000000000000..d70d3e3a357c --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/id_connectedcluster.go @@ -0,0 +1,130 @@ +package connectedclusters + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/recaser" + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +func init() { + recaser.RegisterResourceId(&ConnectedClusterId{}) +} + +var _ resourceids.ResourceId = &ConnectedClusterId{} + +// ConnectedClusterId is a struct representing the Resource ID for a Connected Cluster +type ConnectedClusterId struct { + SubscriptionId string + ResourceGroupName string + ConnectedClusterName string +} + +// NewConnectedClusterID returns a new ConnectedClusterId struct +func NewConnectedClusterID(subscriptionId string, resourceGroupName string, connectedClusterName string) ConnectedClusterId { + return ConnectedClusterId{ + SubscriptionId: subscriptionId, + ResourceGroupName: resourceGroupName, + ConnectedClusterName: connectedClusterName, + } +} + +// ParseConnectedClusterID parses 'input' into a ConnectedClusterId +func ParseConnectedClusterID(input string) (*ConnectedClusterId, error) { + parser := resourceids.NewParserFromResourceIdType(&ConnectedClusterId{}) + parsed, err := parser.Parse(input, false) + if err != nil { + return nil, fmt.Errorf("parsing %q: %+v", input, err) + } + + id := ConnectedClusterId{} + if err := id.FromParseResult(*parsed); err != nil { + return nil, err + } + + return &id, nil +} + +// ParseConnectedClusterIDInsensitively parses 'input' case-insensitively into a ConnectedClusterId +// note: this method should only be used for API response data and not user input +func ParseConnectedClusterIDInsensitively(input string) (*ConnectedClusterId, error) { + parser := resourceids.NewParserFromResourceIdType(&ConnectedClusterId{}) + parsed, err := parser.Parse(input, true) + if err != nil { + return nil, fmt.Errorf("parsing %q: %+v", input, err) + } + + id := ConnectedClusterId{} + if err := id.FromParseResult(*parsed); err != nil { + return nil, err + } + + return &id, nil +} + +func (id *ConnectedClusterId) FromParseResult(input resourceids.ParseResult) error { + var ok bool + + if id.SubscriptionId, ok = input.Parsed["subscriptionId"]; !ok { + return resourceids.NewSegmentNotSpecifiedError(id, "subscriptionId", input) + } + + if id.ResourceGroupName, ok = input.Parsed["resourceGroupName"]; !ok { + return resourceids.NewSegmentNotSpecifiedError(id, "resourceGroupName", input) + } + + if id.ConnectedClusterName, ok = input.Parsed["connectedClusterName"]; !ok { + return resourceids.NewSegmentNotSpecifiedError(id, "connectedClusterName", input) + } + + return nil +} + +// ValidateConnectedClusterID checks that 'input' can be parsed as a Connected Cluster ID +func ValidateConnectedClusterID(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 := ParseConnectedClusterID(v); err != nil { + errors = append(errors, err) + } + + return +} + +// ID returns the formatted Connected Cluster ID +func (id ConnectedClusterId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Kubernetes/connectedClusters/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroupName, id.ConnectedClusterName) +} + +// Segments returns a slice of Resource ID Segments which comprise this Connected Cluster ID +func (id ConnectedClusterId) Segments() []resourceids.Segment { + return []resourceids.Segment{ + resourceids.StaticSegment("staticSubscriptions", "subscriptions", "subscriptions"), + resourceids.SubscriptionIdSegment("subscriptionId", "12345678-1234-9876-4563-123456789012"), + resourceids.StaticSegment("staticResourceGroups", "resourceGroups", "resourceGroups"), + resourceids.ResourceGroupSegment("resourceGroupName", "example-resource-group"), + resourceids.StaticSegment("staticProviders", "providers", "providers"), + resourceids.ResourceProviderSegment("staticMicrosoftKubernetes", "Microsoft.Kubernetes", "Microsoft.Kubernetes"), + resourceids.StaticSegment("staticConnectedClusters", "connectedClusters", "connectedClusters"), + resourceids.UserSpecifiedSegment("connectedClusterName", "connectedClusterValue"), + } +} + +// String returns a human-readable description of this Connected Cluster ID +func (id ConnectedClusterId) String() string { + components := []string{ + fmt.Sprintf("Subscription: %q", id.SubscriptionId), + fmt.Sprintf("Resource Group Name: %q", id.ResourceGroupName), + fmt.Sprintf("Connected Cluster Name: %q", id.ConnectedClusterName), + } + return fmt.Sprintf("Connected Cluster (%s)", strings.Join(components, "\n")) +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclustercreate.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclustercreate.go new file mode 100644 index 000000000000..04be54c4fee2 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclustercreate.go @@ -0,0 +1,75 @@ +package connectedclusters + +import ( + "context" + "fmt" + "net/http" + + "github.com/hashicorp/go-azure-sdk/sdk/client" + "github.com/hashicorp/go-azure-sdk/sdk/client/pollers" + "github.com/hashicorp/go-azure-sdk/sdk/client/resourcemanager" + "github.com/hashicorp/go-azure-sdk/sdk/odata" +) + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type ConnectedClusterCreateOperationResponse struct { + Poller pollers.Poller + HttpResponse *http.Response + OData *odata.OData + Model *ConnectedCluster +} + +// ConnectedClusterCreate ... +func (c ConnectedClustersClient) ConnectedClusterCreate(ctx context.Context, id ConnectedClusterId, input ConnectedCluster) (result ConnectedClusterCreateOperationResponse, err error) { + opts := client.RequestOptions{ + ContentType: "application/json; charset=utf-8", + ExpectedStatusCodes: []int{ + http.StatusCreated, + http.StatusOK, + }, + HttpMethod: http.MethodPut, + Path: id.ID(), + } + + req, err := c.Client.NewRequest(ctx, opts) + if err != nil { + return + } + + if err = req.Marshal(input); err != nil { + return + } + + var resp *client.Response + resp, err = req.Execute(ctx) + if resp != nil { + result.OData = resp.OData + result.HttpResponse = resp.Response + } + if err != nil { + return + } + + result.Poller, err = resourcemanager.PollerFromResponse(resp, c.Client) + if err != nil { + return + } + + return +} + +// ConnectedClusterCreateThenPoll performs ConnectedClusterCreate then polls until it's completed +func (c ConnectedClustersClient) ConnectedClusterCreateThenPoll(ctx context.Context, id ConnectedClusterId, input ConnectedCluster) error { + result, err := c.ConnectedClusterCreate(ctx, id, input) + if err != nil { + return fmt.Errorf("performing ConnectedClusterCreate: %+v", err) + } + + if err := result.Poller.PollUntilDone(ctx); err != nil { + return fmt.Errorf("polling after ConnectedClusterCreate: %+v", err) + } + + return nil +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclusterdelete.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclusterdelete.go new file mode 100644 index 000000000000..26ad549db1b0 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclusterdelete.go @@ -0,0 +1,71 @@ +package connectedclusters + +import ( + "context" + "fmt" + "net/http" + + "github.com/hashicorp/go-azure-sdk/sdk/client" + "github.com/hashicorp/go-azure-sdk/sdk/client/pollers" + "github.com/hashicorp/go-azure-sdk/sdk/client/resourcemanager" + "github.com/hashicorp/go-azure-sdk/sdk/odata" +) + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type ConnectedClusterDeleteOperationResponse struct { + Poller pollers.Poller + HttpResponse *http.Response + OData *odata.OData +} + +// ConnectedClusterDelete ... +func (c ConnectedClustersClient) ConnectedClusterDelete(ctx context.Context, id ConnectedClusterId) (result ConnectedClusterDeleteOperationResponse, err error) { + opts := client.RequestOptions{ + ContentType: "application/json; charset=utf-8", + ExpectedStatusCodes: []int{ + http.StatusAccepted, + http.StatusNoContent, + http.StatusOK, + }, + HttpMethod: http.MethodDelete, + Path: id.ID(), + } + + req, err := c.Client.NewRequest(ctx, opts) + if err != nil { + return + } + + var resp *client.Response + resp, err = req.Execute(ctx) + if resp != nil { + result.OData = resp.OData + result.HttpResponse = resp.Response + } + if err != nil { + return + } + + result.Poller, err = resourcemanager.PollerFromResponse(resp, c.Client) + if err != nil { + return + } + + return +} + +// ConnectedClusterDeleteThenPoll performs ConnectedClusterDelete then polls until it's completed +func (c ConnectedClustersClient) ConnectedClusterDeleteThenPoll(ctx context.Context, id ConnectedClusterId) error { + result, err := c.ConnectedClusterDelete(ctx, id) + if err != nil { + return fmt.Errorf("performing ConnectedClusterDelete: %+v", err) + } + + if err := result.Poller.PollUntilDone(ctx); err != nil { + return fmt.Errorf("polling after ConnectedClusterDelete: %+v", err) + } + + return nil +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclusterget.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclusterget.go new file mode 100644 index 000000000000..9ba97354addb --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclusterget.go @@ -0,0 +1,54 @@ +package connectedclusters + +import ( + "context" + "net/http" + + "github.com/hashicorp/go-azure-sdk/sdk/client" + "github.com/hashicorp/go-azure-sdk/sdk/odata" +) + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type ConnectedClusterGetOperationResponse struct { + HttpResponse *http.Response + OData *odata.OData + Model *ConnectedCluster +} + +// ConnectedClusterGet ... +func (c ConnectedClustersClient) ConnectedClusterGet(ctx context.Context, id ConnectedClusterId) (result ConnectedClusterGetOperationResponse, err error) { + opts := client.RequestOptions{ + ContentType: "application/json; charset=utf-8", + ExpectedStatusCodes: []int{ + http.StatusOK, + }, + HttpMethod: http.MethodGet, + Path: id.ID(), + } + + req, err := c.Client.NewRequest(ctx, opts) + if err != nil { + return + } + + var resp *client.Response + resp, err = req.Execute(ctx) + if resp != nil { + result.OData = resp.OData + result.HttpResponse = resp.Response + } + if err != nil { + return + } + + var model ConnectedCluster + result.Model = &model + + if err = resp.Unmarshal(result.Model); err != nil { + return + } + + return +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclusterlistbyresourcegroup.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclusterlistbyresourcegroup.go new file mode 100644 index 000000000000..4429def6a6fb --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclusterlistbyresourcegroup.go @@ -0,0 +1,106 @@ +package connectedclusters + +import ( + "context" + "fmt" + "net/http" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" + "github.com/hashicorp/go-azure-sdk/sdk/client" + "github.com/hashicorp/go-azure-sdk/sdk/odata" +) + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type ConnectedClusterListByResourceGroupOperationResponse struct { + HttpResponse *http.Response + OData *odata.OData + Model *[]ConnectedCluster +} + +type ConnectedClusterListByResourceGroupCompleteResult struct { + LatestHttpResponse *http.Response + Items []ConnectedCluster +} + +type ConnectedClusterListByResourceGroupCustomPager struct { + NextLink *odata.Link `json:"nextLink"` +} + +func (p *ConnectedClusterListByResourceGroupCustomPager) NextPageLink() *odata.Link { + defer func() { + p.NextLink = nil + }() + + return p.NextLink +} + +// ConnectedClusterListByResourceGroup ... +func (c ConnectedClustersClient) ConnectedClusterListByResourceGroup(ctx context.Context, id commonids.ResourceGroupId) (result ConnectedClusterListByResourceGroupOperationResponse, err error) { + opts := client.RequestOptions{ + ContentType: "application/json; charset=utf-8", + ExpectedStatusCodes: []int{ + http.StatusOK, + }, + HttpMethod: http.MethodGet, + Pager: &ConnectedClusterListByResourceGroupCustomPager{}, + Path: fmt.Sprintf("%s/providers/Microsoft.Kubernetes/connectedClusters", id.ID()), + } + + req, err := c.Client.NewRequest(ctx, opts) + if err != nil { + return + } + + var resp *client.Response + resp, err = req.ExecutePaged(ctx) + if resp != nil { + result.OData = resp.OData + result.HttpResponse = resp.Response + } + if err != nil { + return + } + + var values struct { + Values *[]ConnectedCluster `json:"value"` + } + if err = resp.Unmarshal(&values); err != nil { + return + } + + result.Model = values.Values + + return +} + +// ConnectedClusterListByResourceGroupComplete retrieves all the results into a single object +func (c ConnectedClustersClient) ConnectedClusterListByResourceGroupComplete(ctx context.Context, id commonids.ResourceGroupId) (ConnectedClusterListByResourceGroupCompleteResult, error) { + return c.ConnectedClusterListByResourceGroupCompleteMatchingPredicate(ctx, id, ConnectedClusterOperationPredicate{}) +} + +// ConnectedClusterListByResourceGroupCompleteMatchingPredicate retrieves all the results and then applies the predicate +func (c ConnectedClustersClient) ConnectedClusterListByResourceGroupCompleteMatchingPredicate(ctx context.Context, id commonids.ResourceGroupId, predicate ConnectedClusterOperationPredicate) (result ConnectedClusterListByResourceGroupCompleteResult, err error) { + items := make([]ConnectedCluster, 0) + + resp, err := c.ConnectedClusterListByResourceGroup(ctx, id) + if err != nil { + result.LatestHttpResponse = resp.HttpResponse + err = fmt.Errorf("loading results: %+v", err) + return + } + if resp.Model != nil { + for _, v := range *resp.Model { + if predicate.Matches(v) { + items = append(items, v) + } + } + } + + result = ConnectedClusterListByResourceGroupCompleteResult{ + LatestHttpResponse: resp.HttpResponse, + Items: items, + } + return +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclusterlistbysubscription.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclusterlistbysubscription.go new file mode 100644 index 000000000000..6abe9817dda7 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclusterlistbysubscription.go @@ -0,0 +1,106 @@ +package connectedclusters + +import ( + "context" + "fmt" + "net/http" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" + "github.com/hashicorp/go-azure-sdk/sdk/client" + "github.com/hashicorp/go-azure-sdk/sdk/odata" +) + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type ConnectedClusterListBySubscriptionOperationResponse struct { + HttpResponse *http.Response + OData *odata.OData + Model *[]ConnectedCluster +} + +type ConnectedClusterListBySubscriptionCompleteResult struct { + LatestHttpResponse *http.Response + Items []ConnectedCluster +} + +type ConnectedClusterListBySubscriptionCustomPager struct { + NextLink *odata.Link `json:"nextLink"` +} + +func (p *ConnectedClusterListBySubscriptionCustomPager) NextPageLink() *odata.Link { + defer func() { + p.NextLink = nil + }() + + return p.NextLink +} + +// ConnectedClusterListBySubscription ... +func (c ConnectedClustersClient) ConnectedClusterListBySubscription(ctx context.Context, id commonids.SubscriptionId) (result ConnectedClusterListBySubscriptionOperationResponse, err error) { + opts := client.RequestOptions{ + ContentType: "application/json; charset=utf-8", + ExpectedStatusCodes: []int{ + http.StatusOK, + }, + HttpMethod: http.MethodGet, + Pager: &ConnectedClusterListBySubscriptionCustomPager{}, + Path: fmt.Sprintf("%s/providers/Microsoft.Kubernetes/connectedClusters", id.ID()), + } + + req, err := c.Client.NewRequest(ctx, opts) + if err != nil { + return + } + + var resp *client.Response + resp, err = req.ExecutePaged(ctx) + if resp != nil { + result.OData = resp.OData + result.HttpResponse = resp.Response + } + if err != nil { + return + } + + var values struct { + Values *[]ConnectedCluster `json:"value"` + } + if err = resp.Unmarshal(&values); err != nil { + return + } + + result.Model = values.Values + + return +} + +// ConnectedClusterListBySubscriptionComplete retrieves all the results into a single object +func (c ConnectedClustersClient) ConnectedClusterListBySubscriptionComplete(ctx context.Context, id commonids.SubscriptionId) (ConnectedClusterListBySubscriptionCompleteResult, error) { + return c.ConnectedClusterListBySubscriptionCompleteMatchingPredicate(ctx, id, ConnectedClusterOperationPredicate{}) +} + +// ConnectedClusterListBySubscriptionCompleteMatchingPredicate retrieves all the results and then applies the predicate +func (c ConnectedClustersClient) ConnectedClusterListBySubscriptionCompleteMatchingPredicate(ctx context.Context, id commonids.SubscriptionId, predicate ConnectedClusterOperationPredicate) (result ConnectedClusterListBySubscriptionCompleteResult, err error) { + items := make([]ConnectedCluster, 0) + + resp, err := c.ConnectedClusterListBySubscription(ctx, id) + if err != nil { + result.LatestHttpResponse = resp.HttpResponse + err = fmt.Errorf("loading results: %+v", err) + return + } + if resp.Model != nil { + for _, v := range *resp.Model { + if predicate.Matches(v) { + items = append(items, v) + } + } + } + + result = ConnectedClusterListBySubscriptionCompleteResult{ + LatestHttpResponse: resp.HttpResponse, + Items: items, + } + return +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclusterlistclusterusercredential.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclusterlistclusterusercredential.go new file mode 100644 index 000000000000..6154d1cf2313 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclusterlistclusterusercredential.go @@ -0,0 +1,59 @@ +package connectedclusters + +import ( + "context" + "fmt" + "net/http" + + "github.com/hashicorp/go-azure-sdk/sdk/client" + "github.com/hashicorp/go-azure-sdk/sdk/odata" +) + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type ConnectedClusterListClusterUserCredentialOperationResponse struct { + HttpResponse *http.Response + OData *odata.OData + Model *CredentialResults +} + +// ConnectedClusterListClusterUserCredential ... +func (c ConnectedClustersClient) ConnectedClusterListClusterUserCredential(ctx context.Context, id ConnectedClusterId, input ListClusterUserCredentialProperties) (result ConnectedClusterListClusterUserCredentialOperationResponse, err error) { + opts := client.RequestOptions{ + ContentType: "application/json; charset=utf-8", + ExpectedStatusCodes: []int{ + http.StatusOK, + }, + HttpMethod: http.MethodPost, + Path: fmt.Sprintf("%s/listClusterUserCredential", id.ID()), + } + + req, err := c.Client.NewRequest(ctx, opts) + if err != nil { + return + } + + if err = req.Marshal(input); err != nil { + return + } + + var resp *client.Response + resp, err = req.Execute(ctx) + if resp != nil { + result.OData = resp.OData + result.HttpResponse = resp.Response + } + if err != nil { + return + } + + var model CredentialResults + result.Model = &model + + if err = resp.Unmarshal(result.Model); err != nil { + return + } + + return +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclusterupdate.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclusterupdate.go new file mode 100644 index 000000000000..c4a8cbe1c31a --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/method_connectedclusterupdate.go @@ -0,0 +1,58 @@ +package connectedclusters + +import ( + "context" + "net/http" + + "github.com/hashicorp/go-azure-sdk/sdk/client" + "github.com/hashicorp/go-azure-sdk/sdk/odata" +) + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type ConnectedClusterUpdateOperationResponse struct { + HttpResponse *http.Response + OData *odata.OData + Model *ConnectedCluster +} + +// ConnectedClusterUpdate ... +func (c ConnectedClustersClient) ConnectedClusterUpdate(ctx context.Context, id ConnectedClusterId, input ConnectedClusterPatch) (result ConnectedClusterUpdateOperationResponse, err error) { + opts := client.RequestOptions{ + ContentType: "application/json; charset=utf-8", + ExpectedStatusCodes: []int{ + http.StatusOK, + }, + HttpMethod: http.MethodPatch, + Path: id.ID(), + } + + req, err := c.Client.NewRequest(ctx, opts) + if err != nil { + return + } + + if err = req.Marshal(input); err != nil { + return + } + + var resp *client.Response + resp, err = req.Execute(ctx) + if resp != nil { + result.OData = resp.OData + result.HttpResponse = resp.Response + } + if err != nil { + return + } + + var model ConnectedCluster + result.Model = &model + + if err = resp.Unmarshal(result.Model); err != nil { + return + } + + return +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_connectedcluster.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_connectedcluster.go new file mode 100644 index 000000000000..d1f61f12e1a9 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_connectedcluster.go @@ -0,0 +1,20 @@ +package connectedclusters + +import ( + "github.com/hashicorp/go-azure-helpers/resourcemanager/identity" + "github.com/hashicorp/go-azure-helpers/resourcemanager/systemdata" +) + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type ConnectedCluster struct { + Id *string `json:"id,omitempty"` + Identity identity.SystemAssigned `json:"identity"` + Location string `json:"location"` + Name *string `json:"name,omitempty"` + Properties ConnectedClusterProperties `json:"properties"` + SystemData *systemdata.SystemData `json:"systemData,omitempty"` + Tags *map[string]string `json:"tags,omitempty"` + Type *string `json:"type,omitempty"` +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_connectedclusterpatch.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_connectedclusterpatch.go new file mode 100644 index 000000000000..560b8bccc64f --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_connectedclusterpatch.go @@ -0,0 +1,9 @@ +package connectedclusters + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type ConnectedClusterPatch struct { + Properties *interface{} `json:"properties,omitempty"` + Tags *map[string]string `json:"tags,omitempty"` +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_connectedclusterproperties.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_connectedclusterproperties.go new file mode 100644 index 000000000000..eb7e5c945f1d --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_connectedclusterproperties.go @@ -0,0 +1,49 @@ +package connectedclusters + +import ( + "time" + + "github.com/hashicorp/go-azure-helpers/lang/dates" +) + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type ConnectedClusterProperties struct { + AgentPublicKeyCertificate string `json:"agentPublicKeyCertificate"` + AgentVersion *string `json:"agentVersion,omitempty"` + ConnectivityStatus *ConnectivityStatus `json:"connectivityStatus,omitempty"` + Distribution *string `json:"distribution,omitempty"` + Infrastructure *string `json:"infrastructure,omitempty"` + KubernetesVersion *string `json:"kubernetesVersion,omitempty"` + LastConnectivityTime *string `json:"lastConnectivityTime,omitempty"` + ManagedIdentityCertificateExpirationTime *string `json:"managedIdentityCertificateExpirationTime,omitempty"` + Offering *string `json:"offering,omitempty"` + ProvisioningState *ProvisioningState `json:"provisioningState,omitempty"` + TotalCoreCount *int64 `json:"totalCoreCount,omitempty"` + TotalNodeCount *int64 `json:"totalNodeCount,omitempty"` +} + +func (o *ConnectedClusterProperties) GetLastConnectivityTimeAsTime() (*time.Time, error) { + if o.LastConnectivityTime == nil { + return nil, nil + } + return dates.ParseAsFormat(o.LastConnectivityTime, "2006-01-02T15:04:05Z07:00") +} + +func (o *ConnectedClusterProperties) SetLastConnectivityTimeAsTime(input time.Time) { + formatted := input.Format("2006-01-02T15:04:05Z07:00") + o.LastConnectivityTime = &formatted +} + +func (o *ConnectedClusterProperties) GetManagedIdentityCertificateExpirationTimeAsTime() (*time.Time, error) { + if o.ManagedIdentityCertificateExpirationTime == nil { + return nil, nil + } + return dates.ParseAsFormat(o.ManagedIdentityCertificateExpirationTime, "2006-01-02T15:04:05Z07:00") +} + +func (o *ConnectedClusterProperties) SetManagedIdentityCertificateExpirationTimeAsTime(input time.Time) { + formatted := input.Format("2006-01-02T15:04:05Z07:00") + o.ManagedIdentityCertificateExpirationTime = &formatted +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_credentialresult.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_credentialresult.go new file mode 100644 index 000000000000..dc74c9fd42e6 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_credentialresult.go @@ -0,0 +1,9 @@ +package connectedclusters + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type CredentialResult struct { + Name *string `json:"name,omitempty"` + Value *string `json:"value,omitempty"` +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_credentialresults.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_credentialresults.go new file mode 100644 index 000000000000..a64afb76a343 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_credentialresults.go @@ -0,0 +1,9 @@ +package connectedclusters + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type CredentialResults struct { + HybridConnectionConfig *HybridConnectionConfig `json:"hybridConnectionConfig,omitempty"` + Kubeconfigs *[]CredentialResult `json:"kubeconfigs,omitempty"` +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_hybridconnectionconfig.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_hybridconnectionconfig.go new file mode 100644 index 000000000000..2f2c102d61a2 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_hybridconnectionconfig.go @@ -0,0 +1,11 @@ +package connectedclusters + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type HybridConnectionConfig struct { + ExpirationTime *int64 `json:"expirationTime,omitempty"` + HybridConnectionName *string `json:"hybridConnectionName,omitempty"` + Relay *string `json:"relay,omitempty"` + Token *string `json:"token,omitempty"` +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_listclusterusercredentialproperties.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_listclusterusercredentialproperties.go new file mode 100644 index 000000000000..e8e0c57aaab7 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/model_listclusterusercredentialproperties.go @@ -0,0 +1,9 @@ +package connectedclusters + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type ListClusterUserCredentialProperties struct { + AuthenticationMethod AuthenticationMethod `json:"authenticationMethod"` + ClientProxy bool `json:"clientProxy"` +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/predicates.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/predicates.go new file mode 100644 index 000000000000..a1dcf6aaa3a2 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/predicates.go @@ -0,0 +1,32 @@ +package connectedclusters + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type ConnectedClusterOperationPredicate struct { + Id *string + Location *string + Name *string + Type *string +} + +func (p ConnectedClusterOperationPredicate) Matches(input ConnectedCluster) bool { + + if p.Id != nil && (input.Id == nil || *p.Id != *input.Id) { + return false + } + + if p.Location != nil && *p.Location != input.Location { + return false + } + + if p.Name != nil && (input.Name == nil || *p.Name != *input.Name) { + return false + } + + if p.Type != nil && (input.Type == nil || *p.Type != *input.Type) { + return false + } + + return true +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/version.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/version.go new file mode 100644 index 000000000000..078fe01f8f68 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters/version.go @@ -0,0 +1,12 @@ +package connectedclusters + +import "fmt" + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +const defaultApiVersion = "2021-10-01" + +func userAgent() string { + return fmt.Sprintf("hashicorp/go-azure-sdk/connectedclusters/%s", defaultApiVersion) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 2aa49f2bdde5..244123ac46f8 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -564,6 +564,7 @@ github.com/hashicorp/go-azure-sdk/resource-manager/hybridcompute/2022-11-10/mach github.com/hashicorp/go-azure-sdk/resource-manager/hybridcompute/2022-11-10/machines github.com/hashicorp/go-azure-sdk/resource-manager/hybridcompute/2022-11-10/privateendpointconnections github.com/hashicorp/go-azure-sdk/resource-manager/hybridcompute/2022-11-10/privatelinkscopes +github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2021-10-01/connectedclusters github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2024-01-01/connectedclusters github.com/hashicorp/go-azure-sdk/resource-manager/insights/2015-04-01/activitylogs github.com/hashicorp/go-azure-sdk/resource-manager/insights/2016-03-01/logprofiles diff --git a/website/allowed-subcategories b/website/allowed-subcategories index 481255cd9868..bc4c66a96283 100644 --- a/website/allowed-subcategories +++ b/website/allowed-subcategories @@ -51,6 +51,7 @@ Digital Twins Disks Elastic Elastic SAN +Extended Location Fluid Relay Graph Services HDInsight diff --git a/website/docs/r/extended_location_custom_location.html.markdown b/website/docs/r/extended_location_custom_location.html.markdown new file mode 100644 index 000000000000..caabca074c0a --- /dev/null +++ b/website/docs/r/extended_location_custom_location.html.markdown @@ -0,0 +1,138 @@ +--- +subcategory: "Extended Location" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_extended_location_custom_location" +description: |- + Manages a Custom Location within an Extended Location. +--- + +# azurerm_extended_location_custom_location + +Manages a Custom Location within an Extended Location. + +-> **Note:** Installing and configuring the Azure Arc Agent on your Kubernetes Cluster to establish connectivity is outside the scope of this document. For more details refer to [Deploy agents to your cluster](https://learn.microsoft.com/en-us/azure/azure-arc/kubernetes/conceptual-agent-overview#deploy-agents-to-your-cluster) and [Connect an existing Kubernetes Cluster](https://learn.microsoft.com/en-us/azure/azure-arc/kubernetes/quickstart-connect-cluster?tabs=azure-cli#connect-an-existing-kubernetes-cluster). If you encounter issues connecting your Kubernetes Cluster to Azure Arc, we'd recommend opening a ticket with Microsoft Support. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-resources" + location = "West Europe" +} + +data "azurerm_client_config" "current" {} + +resource "azurerm_arc_kubernetes_cluster" "example" { + name = "example-akcc" + resource_group_name = azurerm_resource_group.example.name + location = "West Europe" + agent_public_key_certificate = filebase64("testdata/public.cer") + + identity { + type = "SystemAssigned" + } + + tags = { + ENV = "Test" + } +} + +resource "local_file" "example" { + depends_on = [ + azurerm_kubernetes_cluster.example, + ] + content = azurerm_kubernetes_cluster.example.kube_config_raw + filename = "${path.module}/kubeconfig-example" +} + +resource "null_resource" "example1" { + depends_on = [ + azurerm_kubernetes_cluster.example, + ] + provisioner "local-exec" { + command = "set KUBECONFIG=${path.module}/kubeconfig-example" + } +} + +resource "null_resource" "example2" { + depends_on = [ + null_resource.example1, + ] + provisioner "local-exec" { + command = "az connectedk8s connect --name example-akcc --resource-group ${azurerm_resource_group.example.name} --subscription ${data.azurerm_client_config.current.subscription_id} --location ${azurerm_resource_group.example.location} --kube-config=${path.module}/kubeconfig-example --kube-context example" + } +} + +resource "azurerm_arc_kubernetes_cluster_extension" "example" { + name = "example-ext" + cluster_id = azurerm_arc_kubernetes_cluster.example.id + extension_type = "microsoft.flux" +} + +resource "azurerm_extended_location_custom_location" "example" { + name = "example-custom-location" + resource_group_name = azurerm_resource_group.example.name + location = "West Europe" + cluster_extension_ids = [ + azurerm_arc_kubernetes_cluster_extension.example.id + ] + display_name = "example-custom-location" + namespace = "example-namespace" + host_resource_id = azurerm_arc_kubernetes_cluster.example.id + authentication { + value = base64encode(azurerm_kubernetes_cluster.example.kube_config_raw) + } +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `name` - (Required) Specifies the name which should be used for this Custom Location. Changing this forces a new Custom Location to be created. + +* `resource_group_name` - (Required) Specifies the name of the Resource Group where the Custom Location should exist. Changing this forces a new Custom Location to be created. + +* `location` - (Required) Specifies the Azure location where the Custom Location should exist. Changing this forces a new Custom Location to be created. + +* `namespace` - (Required) Specifies the namespace of the Custom Location. Changing this forces a new Custom Location to be created. + +* `cluster_extension_ids` - (Required) Specifies the list of Cluster Extension IDs. + +* `host_resource_id` - (Required) Specifies the host resource ID. + +* `authentication` - (Optional) An `authentication` block as defined below. + +* `display_name` - (Optional) Specifies the display name of the Custom Location. + +* `host_type` - (Optional) Specifies the host type of the Custom Location. The only possible values is `KubernetesCluster`. + +--- + +An `authentication` block supports the following: + +* `type` - (Optional) Specifies the type of authentication. + +* `value` - (Required) Specifies the value of authentication. + +## Attributes Reference + +* `id` - The ID of the Custom Location. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/language/resources/syntax#operation-timeouts) for certain actions: + +* `create` - (Defaults to 30 minutes) Used when creating the Custom Location. +* `read` - (Defaults to 5 minutes) Used when retrieving the Custom Location. +* `update` - (Defaults to 30 minutes) Used when updating the Custom Location. +* `delete` - (Defaults to 30 minutes) Used when deleting the Custom Location. + +## Import + +Custom Locations can be imported using the resource id, e.g. + +```shell +terraform import azurerm_extended_location_custom_location.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/example-resources/providers/Microsoft.ExtendedLocation/customLocations/example-custom-location +``` +