From 50e6ebc9c65f7af4f8e4b43434ba50772c667ef1 Mon Sep 17 00:00:00 2001 From: Tao <104055472+teowa@users.noreply.github.com> Date: Tue, 7 Jan 2025 22:48:00 +0800 Subject: [PATCH] new resource `azurerm_arc_kubernetes_provisioned_cluster` (#28216) * new resource azurerm_arc_kubernetes_provisioned_cluster * fix gh-label * fix doc * fix docs * fix code order * fix * fix deleting issue * revert and change test location * go mod vendor --- .github/labeler-issue-triage.yml | 5 +- .github/labeler-pull-request-triage.yml | 5 + .teamcity/components/settings.kt | 3 + ...kubernetes_provisioned_cluster_resource.go | 401 ++++++++++++++++++ ...netes_provisioned_cluster_resource_test.go | 224 ++++++++++ .../services/arckubernetes/registration.go | 9 +- ...bernetes_provisioned_cluster.html.markdown | 129 ++++++ 7 files changed, 773 insertions(+), 3 deletions(-) create mode 100644 internal/services/arckubernetes/arc_kubernetes_provisioned_cluster_resource.go create mode 100644 internal/services/arckubernetes/arc_kubernetes_provisioned_cluster_resource_test.go create mode 100644 website/docs/r/arc_kubernetes_provisioned_cluster.html.markdown diff --git a/.github/labeler-issue-triage.yml b/.github/labeler-issue-triage.yml index b0211680500d..6a042606acd6 100644 --- a/.github/labeler-issue-triage.yml +++ b/.github/labeler-issue-triage.yml @@ -27,11 +27,14 @@ service/app-configuration: - '### (|New or )Affected Resource\(s\)\/Data Source\(s\)((.|\n)*)azurerm_app_configuration((.|\n)*)###' service/app-service: - - '### (|New or )Affected Resource\(s\)\/Data Source\(s\)((.|\n)*)azurerm_(app_service_environment_v3\W+|app_service_environment_v3\W+|app_service_source_control\W+|app_service_source_control_slot\W+|arc_kubernetes_cluster_extension\W+|arc_kubernetes_flux_configuration\W+|function_app_active_slot\W+|function_app_function\W+|function_app_hybrid_connection\W+|linux_function_app\W+|linux_function_app\W+|linux_function_app_slot\W+|linux_web_app\W+|linux_web_app\W+|linux_web_app_slot\W+|service_plan|source_control_token|static_web_app|web_app_|windows_function_app\W+|windows_function_app\W+|windows_function_app_slot\W+|windows_web_app\W+|windows_web_app\W+|windows_web_app_slot\W+)((.|\n)*)###' + - '### (|New or )Affected Resource\(s\)\/Data Source\(s\)((.|\n)*)azurerm_(app_service_environment_v3\W+|app_service_environment_v3\W+|app_service_source_control\W+|app_service_source_control_slot\W+|function_app_active_slot\W+|function_app_function\W+|function_app_hybrid_connection\W+|linux_function_app\W+|linux_function_app\W+|linux_function_app_slot\W+|linux_web_app\W+|linux_web_app\W+|linux_web_app_slot\W+|service_plan|source_control_token|static_web_app|web_app_|windows_function_app\W+|windows_function_app\W+|windows_function_app_slot\W+|windows_web_app\W+|windows_web_app\W+|windows_web_app_slot\W+)((.|\n)*)###' service/application-insights: - '### (|New or )Affected Resource\(s\)\/Data Source\(s\)((.|\n)*)azurerm_application_insights((.|\n)*)###' +service/arc-kubernetes: + - '### (|New or )Affected Resource\(s\)\/Data Source\(s\)((.|\n)*)azurerm_arc_kubernetes_((.|\n)*)###' + service/arc-resource-bridge: - '### (|New or )Affected Resource\(s\)\/Data Source\(s\)((.|\n)*)azurerm_arc_resource_bridge_appliance((.|\n)*)###' diff --git a/.github/labeler-pull-request-triage.yml b/.github/labeler-pull-request-triage.yml index 40edc1b20a7b..f2a786bebfa9 100644 --- a/.github/labeler-pull-request-triage.yml +++ b/.github/labeler-pull-request-triage.yml @@ -52,6 +52,11 @@ service/application-insights: - any-glob-to-any-file: - internal/services/applicationinsights/**/* +service/arc-kubernetes: +- changed-files: + - any-glob-to-any-file: + - internal/services/arckubernetes/**/* + service/arc-resource-bridge: - changed-files: - any-glob-to-any-file: diff --git a/.teamcity/components/settings.kt b/.teamcity/components/settings.kt index 54ee3c4e52ff..2df87ed68bd9 100644 --- a/.teamcity/components/settings.kt +++ b/.teamcity/components/settings.kt @@ -39,6 +39,9 @@ var serviceTestConfigurationOverrides = mapOf( // App Service Plans for Linux are currently unavailable in WestUS2 "appservice" to testConfiguration(startHour = 3, daysOfWeek = "2,4,6", locationOverride = LocationConfiguration("westeurope", "westus2", "eastus2", true)), + // Arc Kubernetes Provisioned Cluster is only available in certain locations + "arckubernetes" to testConfiguration(locationOverride = LocationConfiguration("australiaeast", "eastus", "westeurope", true)), + // these tests all conflict with one another "authorization" to testConfiguration(parallelism = 1), diff --git a/internal/services/arckubernetes/arc_kubernetes_provisioned_cluster_resource.go b/internal/services/arckubernetes/arc_kubernetes_provisioned_cluster_resource.go new file mode 100644 index 000000000000..551c37d629d3 --- /dev/null +++ b/internal/services/arckubernetes/arc_kubernetes_provisioned_cluster_resource.go @@ -0,0 +1,401 @@ +package arckubernetes + +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-helpers/resourcemanager/identity" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + arckubernetes "github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2024-01-01/connectedclusters" + "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" +) + +var ( + _ sdk.Resource = ArcKubernetesProvisionedClusterResource{} + _ sdk.ResourceWithUpdate = ArcKubernetesProvisionedClusterResource{} +) + +// This resource is same type as the ArcKubernetesClusterResource but with kind="ProvisionedCluster". +type ArcKubernetesProvisionedClusterResource struct{} + +type ArcKubernetesProvisionedClusterModel struct { + AgentVersion string `tfschema:"agent_version"` + ArcAgentAutoUpgradeEnabled bool `tfschema:"arc_agent_auto_upgrade_enabled"` + ArcAgentDesiredVersion string `tfschema:"arc_agent_desired_version"` + AzureActiveDirectory []AzureActiveDirectoryModel `tfschema:"azure_active_directory"` + Distribution string `tfschema:"distribution"` + Identity []identity.ModelSystemAssigned `tfschema:"identity"` + Infrastructure string `tfschema:"infrastructure"` + KubernetesVersion string `tfschema:"kubernetes_version"` + Location string `tfschema:"location"` + Name string `tfschema:"name"` + Offering string `tfschema:"offering"` + ResourceGroupName string `tfschema:"resource_group_name"` + Tags map[string]string `tfschema:"tags"` + TotalCoreCount int64 `tfschema:"total_core_count"` + TotalNodeCount int64 `tfschema:"total_node_count"` +} + +type AzureActiveDirectoryModel struct { + AdminGroupObjectIds []string `tfschema:"admin_group_object_ids"` + AzureRbacEnabled bool `tfschema:"azure_rbac_enabled"` + TenantId string `tfschema:"tenant_id"` +} + +func (r ArcKubernetesProvisionedClusterResource) ResourceType() string { + return "azurerm_arc_kubernetes_provisioned_cluster" +} + +func (r ArcKubernetesProvisionedClusterResource) ModelObject() interface{} { + return &ArcKubernetesProvisionedClusterModel{} +} + +func (r ArcKubernetesProvisionedClusterResource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return arckubernetes.ValidateConnectedClusterID +} + +func (r ArcKubernetesProvisionedClusterResource) Arguments() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringMatch( + regexp.MustCompile("^[-_a-zA-Z0-9]{1,260}$"), + "The name of Arc Kubernetes Provisioned Cluster can only include alphanumeric characters, underscores, hyphens, has a maximum length of 260 characters, and must be unique.", + ), + }, + + "resource_group_name": commonschema.ResourceGroupName(), + + "location": commonschema.Location(), + + "identity": commonschema.SystemAssignedIdentityRequiredForceNew(), + + "azure_active_directory": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "admin_group_object_ids": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.IsUUID, + }, + }, + + "azure_rbac_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + + "tenant_id": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.IsUUID, + }, + }, + }, + }, + + "arc_agent_desired_version": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "arc_agent_auto_upgrade_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: true, + }, + + "tags": commonschema.Tags(), + } +} + +func (r ArcKubernetesProvisionedClusterResource) Attributes() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "agent_version": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "distribution": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "infrastructure": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "kubernetes_version": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "offering": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "total_core_count": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "total_node_count": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + } +} + +func (r ArcKubernetesProvisionedClusterResource) Create() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.ArcKubernetes.ArcKubernetesClient + subscriptionId := metadata.Client.Account.SubscriptionId + + var model ArcKubernetesProvisionedClusterModel + if err := metadata.Decode(&model); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + id := arckubernetes.NewConnectedClusterID(subscriptionId, model.ResourceGroupName, model.Name) + + existing, err := client.ConnectedClusterGet(ctx, id) + if err != nil && !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for existing %s: %+v", id, err) + } + + if !response.WasNotFound(existing.HttpResponse) { + return metadata.ResourceRequiresImport(r.ResourceType(), id) + } + + arcAgentAutoUpgrade := arckubernetes.AutoUpgradeOptionsDisabled + if model.ArcAgentAutoUpgradeEnabled { + arcAgentAutoUpgrade = arckubernetes.AutoUpgradeOptionsEnabled + } + + expandedIdentity, err := identity.ExpandSystemAssignedFromModel(model.Identity) + if err != nil { + return fmt.Errorf("expanding `identity`: %+v", err) + } + + payload := &arckubernetes.ConnectedCluster{ + Identity: pointer.From(expandedIdentity), + Location: location.Normalize(model.Location), + Tags: pointer.To(model.Tags), + Kind: pointer.To(arckubernetes.ConnectedClusterKindProvisionedCluster), + Properties: arckubernetes.ConnectedClusterProperties{ + ArcAgentProfile: &arckubernetes.ArcAgentProfile{ + AgentAutoUpgrade: pointer.To(arcAgentAutoUpgrade), + }, + }, + } + + if aadProfileVal := model.AzureActiveDirectory; len(aadProfileVal) != 0 { + payload.Properties.AadProfile = expandArcKubernetesClusterAadProfile(aadProfileVal) + } + + if desiredVersion := model.ArcAgentDesiredVersion; desiredVersion != "" { + payload.Properties.ArcAgentProfile.DesiredAgentVersion = pointer.To(desiredVersion) + } + + if err := client.ConnectedClusterCreateThenPoll(ctx, id, *payload); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + metadata.SetID(id) + + return nil + }, + } +} + +func (r ArcKubernetesProvisionedClusterResource) Update() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.ArcKubernetes.ArcKubernetesClient + + id, err := arckubernetes.ParseConnectedClusterID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + var model ArcKubernetesProvisionedClusterModel + if err := metadata.Decode(&model); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + resp, err := client.ConnectedClusterGet(ctx, *id) + if err != nil { + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + if resp.Model == nil { + return fmt.Errorf("retrieving %s: `model` was nil", *id) + } + payload := resp.Model + + if metadata.ResourceData.HasChange("azure_active_directory") { + payload.Properties.AadProfile = expandArcKubernetesClusterAadProfile(model.AzureActiveDirectory) + } + + if metadata.ResourceData.HasChange("tags") { + payload.Tags = pointer.To(model.Tags) + } + + if metadata.ResourceData.HasChange("arc_agent_desired_version") { + if desiredVersion := model.ArcAgentDesiredVersion; desiredVersion != "" { + payload.Properties.ArcAgentProfile.DesiredAgentVersion = pointer.To(desiredVersion) + } else { + payload.Properties.ArcAgentProfile.DesiredAgentVersion = nil + } + } + + if metadata.ResourceData.HasChange("arc_agent_auto_upgrade_enabled") { + autoUpgradeOption := arckubernetes.AutoUpgradeOptionsEnabled + if !model.ArcAgentAutoUpgradeEnabled { + autoUpgradeOption = arckubernetes.AutoUpgradeOptionsDisabled + } + + payload.Properties.ArcAgentProfile.AgentAutoUpgrade = pointer.To(autoUpgradeOption) + } + + if err := client.ConnectedClusterCreateThenPoll(ctx, *id, *payload); err != nil { + return fmt.Errorf("updating %s: %+v", *id, err) + } + + return nil + }, + } +} + +func (r ArcKubernetesProvisionedClusterResource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.ArcKubernetes.ArcKubernetesClient + + id, err := arckubernetes.ParseConnectedClusterID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + resp, err := client.ConnectedClusterGet(ctx, *id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return metadata.MarkAsGone(id) + } + + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + state := ArcKubernetesProvisionedClusterModel{ + Name: id.ConnectedClusterName, + ResourceGroupName: id.ResourceGroupName, + } + + if model := resp.Model; model != nil { + state.Identity = identity.FlattenSystemAssignedToModel(&model.Identity) + state.Location = location.Normalize(model.Location) + state.Tags = pointer.From(model.Tags) + + props := model.Properties + state.AzureActiveDirectory = flattenArcKubernetesClusterAadProfile(props.AadProfile) + state.AgentVersion = pointer.From(props.AgentVersion) + state.Distribution = pointer.From(props.Distribution) + state.Infrastructure = pointer.From(props.Infrastructure) + state.KubernetesVersion = pointer.From(props.KubernetesVersion) + state.Offering = pointer.From(props.Offering) + state.TotalCoreCount = pointer.From(props.TotalCoreCount) + state.TotalNodeCount = pointer.From(props.TotalNodeCount) + + arcAgentAutoUpgradeEnabled := true + arcAgentdesiredVersion := "" + if arcAgentProfile := props.ArcAgentProfile; arcAgentProfile != nil { + arcAgentdesiredVersion = pointer.From(arcAgentProfile.DesiredAgentVersion) + if arcAgentProfile.AgentAutoUpgrade != nil && *arcAgentProfile.AgentAutoUpgrade == arckubernetes.AutoUpgradeOptionsDisabled { + arcAgentAutoUpgradeEnabled = false + } + } + state.ArcAgentAutoUpgradeEnabled = arcAgentAutoUpgradeEnabled + state.ArcAgentDesiredVersion = arcAgentdesiredVersion + } + + return metadata.Encode(&state) + }, + } +} + +func (r ArcKubernetesProvisionedClusterResource) Delete() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.ArcKubernetes.ArcKubernetesClient + + id, err := arckubernetes.ParseConnectedClusterID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + if err := client.ConnectedClusterDeleteThenPoll(ctx, *id); err != nil { + return fmt.Errorf("deleting %s: %+v", id, err) + } + + return nil + }, + } +} + +func expandArcKubernetesClusterAadProfile(input []AzureActiveDirectoryModel) *arckubernetes.AadProfile { + if len(input) == 0 { + return nil + } + + v := input[0] + output := arckubernetes.AadProfile{ + EnableAzureRBAC: pointer.To(v.AzureRbacEnabled), + } + + if tenantIdVal := v.TenantId; tenantIdVal != "" { + output.TenantID = pointer.To(tenantIdVal) + } + + if groupVal := v.AdminGroupObjectIds; len(groupVal) != 0 { + output.AdminGroupObjectIDs = pointer.To(groupVal) + } + + return &output +} + +func flattenArcKubernetesClusterAadProfile(input *arckubernetes.AadProfile) []AzureActiveDirectoryModel { + if input == nil || (input.EnableAzureRBAC == nil && input.AdminGroupObjectIDs == nil && input.TenantID == nil) { + return make([]AzureActiveDirectoryModel, 0) + } + + return []AzureActiveDirectoryModel{ + { + AzureRbacEnabled: pointer.From(input.EnableAzureRBAC), + AdminGroupObjectIds: pointer.From(input.AdminGroupObjectIDs), + TenantId: pointer.From(input.TenantID), + }, + } +} diff --git a/internal/services/arckubernetes/arc_kubernetes_provisioned_cluster_resource_test.go b/internal/services/arckubernetes/arc_kubernetes_provisioned_cluster_resource_test.go new file mode 100644 index 000000000000..1eb16ce31ef5 --- /dev/null +++ b/internal/services/arckubernetes/arc_kubernetes_provisioned_cluster_resource_test.go @@ -0,0 +1,224 @@ +package arckubernetes_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/go-azure-helpers/lang/pointer" + arckubernetes "github.com/hashicorp/go-azure-sdk/resource-manager/hybridkubernetes/2024-01-01/connectedclusters" + "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" +) + +type ArcKubernetesProvisionedClusterResource struct{} + +func TestAccArcKubernetesProvisionedCluster_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_arc_kubernetes_provisioned_cluster", "test") + r := ArcKubernetesProvisionedClusterResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccArcKubernetesProvisionedCluster_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_arc_kubernetes_provisioned_cluster", "test") + r := ArcKubernetesProvisionedClusterResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + { + Config: r.requiresImport(data), + ExpectError: acceptance.RequiresImportError(data.ResourceType), + }, + }) +} + +func TestAccArcKubernetesProvisionedCluster_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_arc_kubernetes_provisioned_cluster", "test") + r := ArcKubernetesProvisionedClusterResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.update(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccArcKubernetesProvisionedCluster_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_arc_kubernetes_provisioned_cluster", "test") + r := ArcKubernetesProvisionedClusterResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func (r ArcKubernetesProvisionedClusterResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := arckubernetes.ParseConnectedClusterID(state.ID) + if err != nil { + return nil, err + } + + resp, err := clients.ArcKubernetes.ArcKubernetesClient.ConnectedClusterGet(ctx, *id) + if err != nil { + return nil, fmt.Errorf("retrieving %s: %+v", id, err) + } + return pointer.To(resp.Model != nil), nil +} + +func (r ArcKubernetesProvisionedClusterResource) basic(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%[1]s + +resource "azurerm_arc_kubernetes_provisioned_cluster" "test" { + name = "acctest-akpc-%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + identity { + type = "SystemAssigned" + } +} +`, template, data.RandomInteger) +} + +func (r ArcKubernetesProvisionedClusterResource) requiresImport(data acceptance.TestData) string { + config := r.basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_arc_kubernetes_provisioned_cluster" "import" { + name = azurerm_arc_kubernetes_provisioned_cluster.test.name + resource_group_name = azurerm_arc_kubernetes_provisioned_cluster.test.resource_group_name + location = azurerm_arc_kubernetes_provisioned_cluster.test.location + identity { + type = "SystemAssigned" + } +} +`, config) +} + +func (r ArcKubernetesProvisionedClusterResource) update(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%[1]s + +resource "azurerm_arc_kubernetes_provisioned_cluster" "test" { + name = "acctest-akpc-%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + arc_agent_auto_upgrade_enabled = false + identity { + type = "SystemAssigned" + } + + azure_active_directory { + azure_rbac_enabled = false + } + + tags = { + ENV = "TestUpdate" + } +} +`, template, data.RandomInteger) +} + +func (r ArcKubernetesProvisionedClusterResource) complete(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%[1]s + +data "azurerm_client_config" "current" {} + +resource "azuread_group" "test" { + display_name = "acctestADG-arck8s-%[2]d" + owners = [data.azurerm_client_config.current.object_id] + security_enabled = true +} + +resource "azurerm_arc_kubernetes_provisioned_cluster" "test" { + name = "acctest-akpc-%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + arc_agent_auto_upgrade_enabled = true + arc_agent_desired_version = "1.18.3" + identity { + type = "SystemAssigned" + } + + azure_active_directory { + azure_rbac_enabled = true + admin_group_object_ids = [azuread_group.test.id] + tenant_id = data.azurerm_client_config.current.tenant_id + } + + tags = { + ENV = "Test" + FOO = "BAR" + } +} +`, template, data.RandomInteger) +} + +func (r ArcKubernetesProvisionedClusterResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-akpc-%[1]d" + location = "%[2]s" +} +`, data.RandomInteger, data.Locations.Primary) +} diff --git a/internal/services/arckubernetes/registration.go b/internal/services/arckubernetes/registration.go index ff205f7f0004..ff4a1bd27f25 100644 --- a/internal/services/arckubernetes/registration.go +++ b/internal/services/arckubernetes/registration.go @@ -11,8 +11,8 @@ import ( type Registration struct{} var ( - _ sdk.TypedServiceRegistration = Registration{} - _ sdk.UntypedServiceRegistration = Registration{} + _ sdk.TypedServiceRegistrationWithAGitHubLabel = Registration{} + _ sdk.UntypedServiceRegistrationWithAGitHubLabel = Registration{} ) // Name is the name of this Service @@ -27,6 +27,10 @@ func (r Registration) WebsiteCategories() []string { } } +func (r Registration) AssociatedGitHubLabel() string { + return "service/arc-kubernetes" +} + // SupportedDataSources returns the supported Data Sources supported by this Service func (r Registration) SupportedDataSources() map[string]*pluginsdk.Resource { return map[string]*pluginsdk.Resource{} @@ -47,5 +51,6 @@ func (r Registration) Resources() []sdk.Resource { return []sdk.Resource{ ArcKubernetesClusterExtensionResource{}, ArcKubernetesFluxConfigurationResource{}, + ArcKubernetesProvisionedClusterResource{}, } } diff --git a/website/docs/r/arc_kubernetes_provisioned_cluster.html.markdown b/website/docs/r/arc_kubernetes_provisioned_cluster.html.markdown new file mode 100644 index 000000000000..ab27b73eed17 --- /dev/null +++ b/website/docs/r/arc_kubernetes_provisioned_cluster.html.markdown @@ -0,0 +1,129 @@ +--- +subcategory: "ArcKubernetes" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_arc_kubernetes_provisioned_cluster" +description: |- + Manages an Arc Kubernetes Provisioned Cluster. +--- + +# azurerm_arc_kubernetes_provisioned_cluster + +Manages an Arc Kubernetes Provisioned Cluster. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-resources" + location = "West Europe" +} + +data "azurerm_client_config" "current" {} + +resource "azuread_group" "example" { + display_name = "example-adg" + owners = [data.azurerm_client_config.current.object_id] + security_enabled = true +} + +resource "azurerm_arc_kubernetes_provisioned_cluster" "example" { + name = "example-akpc" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + + azure_active_directory { + azure_rbac_enabled = true + admin_group_object_ids = [azuread_group.example.id] + tenant_id = data.azurerm_client_config.current.tenant_id + } + + identity { + type = "SystemAssigned" + } +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `name` - (Required) The name which should be used for this Arc Kubernetes Provisioned Cluster. Changing this forces a new Arc Kubernetes Provisioned Cluster to be created. + +* `resource_group_name` - (Required) The name of the Resource Group where the Arc Kubernetes Provisioned Cluster should exist. Changing this forces a new Arc Kubernetes Provisioned Cluster to be created. + +* `identity` - (Required) An `identity` block as defined below. Changing this forces a new Arc Kubernetes Provisioned Cluster to be created. + +* `location` - (Required) The Azure Region where the Arc Kubernetes Provisioned Cluster should exist. Changing this forces a new Arc Kubernetes Provisioned Cluster to be created. + +--- + +* `arc_agent_auto_upgrade_enabled` - (Optional) Whether the Arc agents will be upgraded automatically to the latest version. Defaults to `true`. + +* `arc_agent_desired_version` - (Optional) The version of the Arc agents to be installed on the cluster. + +* `azure_active_directory` - (Optional) An `azure_active_directory` block as defined below. + +* `tags` - (Optional) A mapping of tags which should be assigned to the Arc Kubernetes Provisioned Cluster. + +--- + +An `azure_active_directory` block supports the following: + +* `admin_group_object_ids` - (Optional) A list of IDs of Microsoft Entra ID Groups. All members of the specified Microsoft Entra ID Groups have the cluster administrator access to the Kubernetes cluster. + +* `azure_rbac_enabled` - (Optional) Whether to enable Azure RBAC for Kubernetes authorization. Defaults to `false`. + +* `tenant_id` - (Optional) The Tenant ID to use for authentication. If not specified, the Tenant of the Arc Kubernetes Cluster will be used. + +--- + +An `identity` block supports the following: + +* `type` - (Required) The type of the Managed Identity. The only possible value is `SystemAssigned`. Changing this forces a new Arc Kubernetes Provisioned Cluster to be created. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the Arc Kubernetes Provisioned Cluster. + +* `agent_version` - The version of the agent running on the cluster resource. + +* `distribution` - The distribution running on this Arc Kubernetes Provisioned Cluster. + +* `identity` - An `identity` block as defined below. + +* `infrastructure` - The infrastructure on which the Arc Kubernetes Provisioned Cluster is running on. + +* `kubernetes_version` - The Kubernetes version of the cluster resource. + +* `offering` - The cluster offering. + +* `total_core_count` - The number of CPU cores present in the cluster resource. + +* `total_node_count` - The number of nodes present in the cluster resource. + +--- + +An `identity` block exports the following: + +* `principal_id` - The Principal ID associated with this Managed Service Identity. + +* `tenant_id` - The Tenant ID associated with this Managed Service Identity. + +## 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 Arc Kubernetes Provisioned Cluster. +* `read` - (Defaults to 5 minutes) Used when retrieving the Arc Kubernetes Provisioned Cluster. +* `update` - (Defaults to 30 minutes) Used when updating the Arc Kubernetes Provisioned Cluster. +* `delete` - (Defaults to 30 minutes) Used when deleting the Arc Kubernetes Provisioned Cluster. + +## Import + +Arc Kubernetes Provisioned Clusters can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_arc_kubernetes_provisioned_cluster.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1/providers/Microsoft.Kubernetes/connectedClusters/cluster1 +```