From afd18795963b9ca15f750a390603a1c5fbef36ba Mon Sep 17 00:00:00 2001 From: Heng Lu <79895375+ms-henglu@users.noreply.github.com> Date: Tue, 27 Feb 2024 15:27:13 +0800 Subject: [PATCH] new resource: `azurerm_kubernetes_fleet_update_run` (#24813) * new resource: `azurerm_kubernetes_fleet_update_run` * make terrafmt * update doc --- internal/services/containers/client/client.go | 9 + .../kubernetes_fleet_update_run_resource.go | 433 ++++++++++++++++++ ...bernetes_fleet_update_run_resource_test.go | 228 +++++++++ internal/services/containers/registration.go | 1 + .../kubernetes_fleet_update_run.html.markdown | 150 ++++++ 5 files changed, 821 insertions(+) create mode 100644 internal/services/containers/kubernetes_fleet_update_run_resource.go create mode 100644 internal/services/containers/kubernetes_fleet_update_run_resource_test.go create mode 100644 website/docs/r/kubernetes_fleet_update_run.html.markdown diff --git a/internal/services/containers/client/client.go b/internal/services/containers/client/client.go index 60393e0f6b84..d7b4c4f5912e 100644 --- a/internal/services/containers/client/client.go +++ b/internal/services/containers/client/client.go @@ -16,6 +16,7 @@ import ( "github.com/hashicorp/go-azure-sdk/resource-manager/containerservice/2023-06-02-preview/managedclusters" "github.com/hashicorp/go-azure-sdk/resource-manager/containerservice/2023-06-02-preview/snapshots" "github.com/hashicorp/go-azure-sdk/resource-manager/containerservice/2023-10-15/fleetupdatestrategies" + "github.com/hashicorp/go-azure-sdk/resource-manager/containerservice/2023-10-15/updateruns" "github.com/hashicorp/go-azure-sdk/resource-manager/kubernetesconfiguration/2022-11-01/extensions" "github.com/hashicorp/go-azure-sdk/resource-manager/kubernetesconfiguration/2022-11-01/fluxconfiguration" "github.com/hashicorp/go-azure-sdk/sdk/client/resourcemanager" @@ -28,6 +29,7 @@ type Client struct { ContainerRegistryClient_v2021_08_01_preview *containerregistry_v2021_08_01_preview.Client // v2019_06_01_preview is needed for container registry agent pools and tasks ContainerRegistryClient_v2019_06_01_preview *containerregistry_v2019_06_01_preview.Client + FleetUpdateRunsClient *updateruns.UpdateRunsClient FleetUpdateStrategiesClient *fleetupdatestrategies.FleetUpdateStrategiesClient KubernetesClustersClient *managedclusters.ManagedClustersClient KubernetesExtensionsClient *extensions.ExtensionsClient @@ -57,6 +59,12 @@ func NewContainersClient(o *common.ClientOptions) (*Client, error) { } // AKS + fleetUpdateRunsClient, err := updateruns.NewUpdateRunsClientWithBaseURI(o.Environment.ResourceManager) + if err != nil { + return nil, fmt.Errorf("building Fleet Update Runs Client: %+v", err) + } + o.Configure(fleetUpdateRunsClient.Client, o.Authorizers.ResourceManager) + fleetUpdateStrategiesClient, err := fleetupdatestrategies.NewFleetUpdateStrategiesClientWithBaseURI(o.Environment.ResourceManager) if err != nil { return nil, fmt.Errorf("building Fleet Update Strategies Client: %+v", err) @@ -110,6 +118,7 @@ func NewContainersClient(o *common.ClientOptions) (*Client, error) { ContainerInstanceClient: &containerInstanceClient, ContainerRegistryClient_v2021_08_01_preview: containerRegistryClient_v2021_08_01_preview, ContainerRegistryClient_v2019_06_01_preview: containerRegistryClient_v2019_06_01_preview, + FleetUpdateRunsClient: fleetUpdateRunsClient, FleetUpdateStrategiesClient: fleetUpdateStrategiesClient, KubernetesClustersClient: kubernetesClustersClient, KubernetesExtensionsClient: kubernetesExtensionsClient, diff --git a/internal/services/containers/kubernetes_fleet_update_run_resource.go b/internal/services/containers/kubernetes_fleet_update_run_resource.go new file mode 100644 index 000000000000..fd2b58bfef56 --- /dev/null +++ b/internal/services/containers/kubernetes_fleet_update_run_resource.go @@ -0,0 +1,433 @@ +package containers + +import ( + "context" + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/pointer" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-sdk/resource-manager/containerservice/2023-10-15/updateruns" + "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 = KubernetesFleetUpdateRunResource{} +var _ sdk.ResourceWithUpdate = KubernetesFleetUpdateRunResource{} + +type KubernetesFleetUpdateRunResource struct{} + +func (r KubernetesFleetUpdateRunResource) ModelObject() interface{} { + return &KubernetesFleetUpdateRunResourceSchema{} +} + +type KubernetesFleetUpdateRunResourceSchema struct { + KubernetesFleetManagerId string `tfschema:"kubernetes_fleet_manager_id"` + Name string `tfschema:"name"` + ManagedClusterUpdate []KubernetesFleetUpdateRunResourceManagedClusterUpdateSchema `tfschema:"managed_cluster_update"` + FleetUpdateStrategyId string `tfschema:"fleet_update_strategy_id"` + Stage []KubernetesFleetUpdateRunResourceUpdateStageSchema `tfschema:"stage"` +} + +type KubernetesFleetUpdateRunResourceManagedClusterUpdateSchema struct { + NodeImageSelection []KubernetesFleetUpdateRunResourceManagedClusterUpdateNodeImageSelectionSchema `tfschema:"node_image_selection"` + Upgrade []KubernetesFleetUpdateRunResourceManagedClusterUpdateUpgradeSchema `tfschema:"upgrade"` +} + +type KubernetesFleetUpdateRunResourceManagedClusterUpdateNodeImageSelectionSchema struct { + Type string `tfschema:"type"` +} + +type KubernetesFleetUpdateRunResourceManagedClusterUpdateUpgradeSchema struct { + Type string `tfschema:"type"` + KubernetesVersion string `tfschema:"kubernetes_version"` +} + +type KubernetesFleetUpdateRunResourceUpdateGroupSchema struct { + Name string `tfschema:"name"` +} + +type KubernetesFleetUpdateRunResourceUpdateStageSchema struct { + AfterStageWaitInSeconds int64 `tfschema:"after_stage_wait_in_seconds"` + Group []KubernetesFleetUpdateRunResourceUpdateGroupSchema `tfschema:"group"` + Name string `tfschema:"name"` +} + +func (r KubernetesFleetUpdateRunResource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return updateruns.ValidateUpdateRunID +} + +func (r KubernetesFleetUpdateRunResource) ResourceType() string { + return "azurerm_kubernetes_fleet_update_run" +} + +func (r KubernetesFleetUpdateRunResource) Arguments() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + ForceNew: true, + Required: true, + Type: pluginsdk.TypeString, + }, + + "kubernetes_fleet_manager_id": commonschema.ResourceIDReferenceRequiredForceNew(&commonids.KubernetesFleetId{}), + + "managed_cluster_update": { + Required: true, + Type: pluginsdk.TypeList, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "upgrade": { + Required: true, + Type: pluginsdk.TypeList, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "type": { + Required: true, + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(updateruns.ManagedClusterUpgradeTypeFull), + string(updateruns.ManagedClusterUpgradeTypeNodeImageOnly), + }, false), + }, + + "kubernetes_version": { + Optional: true, + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + }, + + "node_image_selection": { + Optional: true, + Type: pluginsdk.TypeList, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "type": { + Required: true, + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(updateruns.NodeImageSelectionTypeConsistent), + string(updateruns.NodeImageSelectionTypeLatest), + }, false), + }, + }, + }, + }, + }, + }, + }, + + "fleet_update_strategy_id": { + Optional: true, + Type: pluginsdk.TypeString, + ConflictsWith: []string{"stage"}, + }, + + "stage": { + Optional: true, + Type: pluginsdk.TypeList, + ConflictsWith: []string{"fleet_update_strategy_id"}, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Required: true, + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "group": { + Required: true, + Type: pluginsdk.TypeList, + MinItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Required: true, + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + }, + + "after_stage_wait_in_seconds": { + Optional: true, + Type: pluginsdk.TypeInt, + }, + }, + }, + }, + } +} + +func (r KubernetesFleetUpdateRunResource) Attributes() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{} +} + +func (r KubernetesFleetUpdateRunResource) Create() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Containers.FleetUpdateRunsClient + + var config KubernetesFleetUpdateRunResourceSchema + if err := metadata.Decode(&config); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + fleetId, err := commonids.ParseKubernetesFleetID(config.KubernetesFleetManagerId) + if err != nil { + return err + } + + id := updateruns.NewUpdateRunID(fleetId.SubscriptionId, fleetId.ResourceGroupName, fleetId.FleetName, config.Name) + + existing, err := client.Get(ctx, id) + if err != nil { + if !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for the presence of an existing %s: %+v", id, err) + } + } + if !response.WasNotFound(existing.HttpResponse) { + return metadata.ResourceRequiresImport(r.ResourceType(), id) + } + + payload := updateruns.UpdateRun{ + Properties: &updateruns.UpdateRunProperties{ + ManagedClusterUpdate: expandKubernetesFleetUpdateRunManagedClusterUpdate(config.ManagedClusterUpdate), + Strategy: expandKubernetesFleetUpdateRunStrategy(config.Stage), + UpdateStrategyId: pointer.To(config.FleetUpdateStrategyId), + }, + } + + if err := client.CreateOrUpdateThenPoll(ctx, id, payload, updateruns.DefaultCreateOrUpdateOperationOptions()); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + metadata.SetID(id) + return nil + }, + } +} + +func (r KubernetesFleetUpdateRunResource) Update() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Containers.FleetUpdateRunsClient + + id, err := updateruns.ParseUpdateRunID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + var config KubernetesFleetUpdateRunResourceSchema + if err := metadata.Decode(&config); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + existing, err := client.Get(ctx, *id) + if err != nil { + return fmt.Errorf("retrieving existing %s: %+v", *id, err) + } + if existing.Model == nil { + return fmt.Errorf("retrieving existing %s: properties was nil", *id) + } + payload := *existing.Model + + if metadata.ResourceData.HasChange("managed_cluster_update") { + payload.Properties.ManagedClusterUpdate = expandKubernetesFleetUpdateRunManagedClusterUpdate(config.ManagedClusterUpdate) + } + + if metadata.ResourceData.HasChange("fleet_update_strategy_id") { + payload.Properties.UpdateStrategyId = pointer.To(config.FleetUpdateStrategyId) + } + + if metadata.ResourceData.HasChange("stage") { + payload.Properties.Strategy.Stages = expandKubernetesFleetUpdateRunStage(config.Stage) + } + + if err := client.CreateOrUpdateThenPoll(ctx, *id, payload, updateruns.DefaultCreateOrUpdateOperationOptions()); err != nil { + return fmt.Errorf("updating %s: %+v", *id, err) + } + + return nil + }, + } +} + +func (r KubernetesFleetUpdateRunResource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Containers.FleetUpdateRunsClient + schema := KubernetesFleetUpdateRunResourceSchema{} + + id, err := updateruns.ParseUpdateRunID(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("retrieving %s: %+v", *id, err) + } + + if model := resp.Model; model != nil { + schema.Name = id.UpdateRunName + schema.KubernetesFleetManagerId = commonids.NewKubernetesFleetID(id.SubscriptionId, id.ResourceGroupName, id.FleetName).ID() + if model.Properties != nil { + schema.ManagedClusterUpdate = flattenKubernetesFleetUpdateRunManagedClusterUpdate(model.Properties.ManagedClusterUpdate) + schema.FleetUpdateStrategyId = pointer.From(model.Properties.UpdateStrategyId) + schema.Stage = flattenKubernetesFleetUpdateRunStage(model.Properties.Strategy.Stages) + } + } + + return metadata.Encode(&schema) + }, + } +} + +func (r KubernetesFleetUpdateRunResource) Delete() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Containers.FleetUpdateRunsClient + + id, err := updateruns.ParseUpdateRunID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + if err := client.DeleteThenPoll(ctx, *id, updateruns.DefaultDeleteOperationOptions()); err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) + } + + return nil + }, + } +} + +func expandKubernetesFleetUpdateRunManagedClusterUpdate(input []KubernetesFleetUpdateRunResourceManagedClusterUpdateSchema) updateruns.ManagedClusterUpdate { + if len(input) == 0 { + return updateruns.ManagedClusterUpdate{} + } + return updateruns.ManagedClusterUpdate{ + NodeImageSelection: expandKubernetesFleetUpdateRunNodeImageSelection(input[0].NodeImageSelection), + Upgrade: expandKubernetesFleetUpdateRunUpgrade(input[0].Upgrade), + } +} + +func expandKubernetesFleetUpdateRunUpgrade(input []KubernetesFleetUpdateRunResourceManagedClusterUpdateUpgradeSchema) updateruns.ManagedClusterUpgradeSpec { + if len(input) == 0 { + return updateruns.ManagedClusterUpgradeSpec{} + } + return updateruns.ManagedClusterUpgradeSpec{ + Type: updateruns.ManagedClusterUpgradeType(input[0].Type), + KubernetesVersion: pointer.To(input[0].KubernetesVersion), + } +} + +func expandKubernetesFleetUpdateRunNodeImageSelection(input []KubernetesFleetUpdateRunResourceManagedClusterUpdateNodeImageSelectionSchema) *updateruns.NodeImageSelection { + if len(input) == 0 { + return nil + } + return &updateruns.NodeImageSelection{ + Type: updateruns.NodeImageSelectionType(input[0].Type), + } +} + +func expandKubernetesFleetUpdateRunStrategy(input []KubernetesFleetUpdateRunResourceUpdateStageSchema) *updateruns.UpdateRunStrategy { + if len(input) == 0 { + return nil + } + + return &updateruns.UpdateRunStrategy{ + Stages: expandKubernetesFleetUpdateRunStage(input), + } +} + +func expandKubernetesFleetUpdateRunStage(input []KubernetesFleetUpdateRunResourceUpdateStageSchema) []updateruns.UpdateStage { + output := make([]updateruns.UpdateStage, 0) + for _, stage := range input { + output = append(output, updateruns.UpdateStage{ + Name: stage.Name, + AfterStageWaitInSeconds: pointer.FromInt64(stage.AfterStageWaitInSeconds), + Groups: expandKubernetesFleetUpdateRunGroup(stage.Group), + }) + } + return output +} + +func expandKubernetesFleetUpdateRunGroup(input []KubernetesFleetUpdateRunResourceUpdateGroupSchema) *[]updateruns.UpdateGroup { + output := make([]updateruns.UpdateGroup, 0) + for _, group := range input { + output = append(output, updateruns.UpdateGroup{ + Name: group.Name, + }) + } + return &output +} + +func flattenKubernetesFleetUpdateRunManagedClusterUpdate(input updateruns.ManagedClusterUpdate) []KubernetesFleetUpdateRunResourceManagedClusterUpdateSchema { + return []KubernetesFleetUpdateRunResourceManagedClusterUpdateSchema{ + { + NodeImageSelection: flattenKubernetesFleetUpdateRunNodeImageSelection(input.NodeImageSelection), + Upgrade: flattenKubernetesFleetUpdateRunUpgrade(input.Upgrade), + }, + } +} + +func flattenKubernetesFleetUpdateRunNodeImageSelection(input *updateruns.NodeImageSelection) []KubernetesFleetUpdateRunResourceManagedClusterUpdateNodeImageSelectionSchema { + if input == nil { + return []KubernetesFleetUpdateRunResourceManagedClusterUpdateNodeImageSelectionSchema{} + } + return []KubernetesFleetUpdateRunResourceManagedClusterUpdateNodeImageSelectionSchema{ + { + Type: string(input.Type), + }, + } +} + +func flattenKubernetesFleetUpdateRunUpgrade(input updateruns.ManagedClusterUpgradeSpec) []KubernetesFleetUpdateRunResourceManagedClusterUpdateUpgradeSchema { + return []KubernetesFleetUpdateRunResourceManagedClusterUpdateUpgradeSchema{ + { + Type: string(input.Type), + KubernetesVersion: pointer.From(input.KubernetesVersion), + }, + } +} + +func flattenKubernetesFleetUpdateRunStage(input []updateruns.UpdateStage) []KubernetesFleetUpdateRunResourceUpdateStageSchema { + output := make([]KubernetesFleetUpdateRunResourceUpdateStageSchema, 0) + for _, stage := range input { + output = append(output, KubernetesFleetUpdateRunResourceUpdateStageSchema{ + Name: stage.Name, + AfterStageWaitInSeconds: pointer.ToInt64(stage.AfterStageWaitInSeconds), + Group: flattenKubernetesFleetUpdateRunGroup(stage.Groups), + }) + } + return output + +} + +func flattenKubernetesFleetUpdateRunGroup(input *[]updateruns.UpdateGroup) []KubernetesFleetUpdateRunResourceUpdateGroupSchema { + output := make([]KubernetesFleetUpdateRunResourceUpdateGroupSchema, 0) + for _, group := range *input { + output = append(output, KubernetesFleetUpdateRunResourceUpdateGroupSchema{ + Name: group.Name, + }) + } + return output +} diff --git a/internal/services/containers/kubernetes_fleet_update_run_resource_test.go b/internal/services/containers/kubernetes_fleet_update_run_resource_test.go new file mode 100644 index 000000000000..111fb39d88a0 --- /dev/null +++ b/internal/services/containers/kubernetes_fleet_update_run_resource_test.go @@ -0,0 +1,228 @@ +package containers_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/go-azure-helpers/lang/pointer" + "github.com/hashicorp/go-azure-sdk/resource-manager/containerservice/2023-10-15/updateruns" + "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 KubernetesFleetUpdateRunTestResource struct{} + +func TestAccKubernetesFleetUpdateRun_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kubernetes_fleet_update_run", "test") + r := KubernetesFleetUpdateRunTestResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccKubernetesFleetUpdateRun_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kubernetes_fleet_update_run", "test") + r := KubernetesFleetUpdateRunTestResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccKubernetesFleetUpdateRun_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kubernetes_fleet_update_run", "test") + r := KubernetesFleetUpdateRunTestResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccKubernetesFleetUpdateRun_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kubernetes_fleet_update_run", "test") + r := KubernetesFleetUpdateRunTestResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(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 (r KubernetesFleetUpdateRunTestResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := updateruns.ParseUpdateRunID(state.ID) + if err != nil { + return nil, err + } + + resp, err := clients.Containers.FleetUpdateRunsClient.Get(ctx, *id) + if err != nil { + return nil, fmt.Errorf("reading %s: %+v", *id, err) + } + + return pointer.To(resp.Model != nil), nil +} +func (r KubernetesFleetUpdateRunTestResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_kubernetes_fleet_update_run" "test" { + name = "acctestfus-%[2]d" + kubernetes_fleet_manager_id = azurerm_kubernetes_fleet_manager.test.id + managed_cluster_update { + upgrade { + type = "NodeImageOnly" + } + } + fleet_update_strategy_id = azurerm_kubernetes_fleet_update_strategy.test.id + + lifecycle { + ignore_changes = [stage] + } + depends_on = [azurerm_kubernetes_fleet_member.test] +} +`, r.template(data), data.RandomInteger) +} + +func (r KubernetesFleetUpdateRunTestResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_kubernetes_fleet_update_run" "import" { + name = azurerm_kubernetes_fleet_update_run.test.name + kubernetes_fleet_manager_id = azurerm_kubernetes_fleet_update_run.test.kubernetes_fleet_manager_id + managed_cluster_update { + upgrade { + type = "NodeImageOnly" + } + } + fleet_update_strategy_id = azurerm_kubernetes_fleet_update_strategy.test.id +} +`, r.basic(data)) +} + +func (r KubernetesFleetUpdateRunTestResource) complete(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_kubernetes_fleet_update_run" "test" { + name = "acctestfus-%[2]d" + kubernetes_fleet_manager_id = azurerm_kubernetes_fleet_manager.test.id + managed_cluster_update { + upgrade { + type = "Full" + kubernetes_version = "1.27" + } + node_image_selection { + type = "Latest" + } + } + stage { + name = "acctestfus-%[2]d" + group { + name = "acctestfus-%[2]d" + } + after_stage_wait_in_seconds = 21 + } + + depends_on = [azurerm_kubernetes_fleet_member.test] +} +`, r.template(data), data.RandomInteger) +} + +func (r KubernetesFleetUpdateRunTestResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` + +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctest-rg-%[2]d" + location = "%[1]s" +} + +resource "azurerm_kubernetes_fleet_manager" "test" { + location = azurerm_resource_group.test.location + name = "acctestkfm-%[2]d" + resource_group_name = azurerm_resource_group.test.name + hub_profile { + dns_prefix = "val-%[2]d" + } +} + +resource "azurerm_kubernetes_cluster" "test" { + name = "acctestkc-%[2]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + dns_prefix = "acctestkc-%[2]d" + + default_node_pool { + name = "default" + node_count = 1 + vm_size = "Standard_DS2_v2" + } + + identity { + type = "SystemAssigned" + } +} + +resource "azurerm_kubernetes_fleet_member" "test" { + name = "acctestkfm-%[2]d" + kubernetes_fleet_id = azurerm_kubernetes_fleet_manager.test.id + kubernetes_cluster_id = azurerm_kubernetes_cluster.test.id + group = "acctestfus-%[2]d" +} + +resource "azurerm_kubernetes_fleet_update_strategy" "test" { + name = "acctestfus-%[2]d" + kubernetes_fleet_manager_id = azurerm_kubernetes_fleet_manager.test.id + stage { + name = "acctestfus-%[2]d" + group { + name = "acctestfus-%[2]d" + } + } +} +`, data.Locations.Primary, data.RandomInteger) +} diff --git a/internal/services/containers/registration.go b/internal/services/containers/registration.go index b2658f5d1c37..812a976ed082 100644 --- a/internal/services/containers/registration.go +++ b/internal/services/containers/registration.go @@ -74,6 +74,7 @@ func (r Registration) Resources() []sdk.Resource { ContainerConnectedRegistryResource{}, KubernetesClusterExtensionResource{}, KubernetesFluxConfigurationResource{}, + KubernetesFleetUpdateRunResource{}, KubernetesFleetUpdateStrategyResource{}, } resources = append(resources, r.autoRegistration.Resources()...) diff --git a/website/docs/r/kubernetes_fleet_update_run.html.markdown b/website/docs/r/kubernetes_fleet_update_run.html.markdown new file mode 100644 index 000000000000..73deeed30fac --- /dev/null +++ b/website/docs/r/kubernetes_fleet_update_run.html.markdown @@ -0,0 +1,150 @@ +--- +subcategory: "Container" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_kubernetes_fleet_update_run" +description: |- + Manages a Kubernetes Fleet Update Run. +--- + +# azurerm_kubernetes_fleet_update_run + +Manages a Kubernetes Fleet Update Run. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-rg" + location = "westeurope" +} + +resource "azurerm_kubernetes_fleet_manager" "example" { + location = azurerm_resource_group.example.location + name = "example" + resource_group_name = azurerm_resource_group.example.name + hub_profile { + dns_prefix = "example-dns-prefix" + } +} + + +resource "azurerm_kubernetes_cluster" "example" { + name = "example" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + dns_prefix = "example" + + default_node_pool { + name = "default" + node_count = 1 + vm_size = "Standard_DS2_v2" + } + + identity { + type = "SystemAssigned" + } +} + +resource "azurerm_kubernetes_fleet_member" "example" { + name = "example" + kubernetes_fleet_id = azurerm_kubernetes_fleet_manager.example.id + kubernetes_cluster_id = azurerm_kubernetes_cluster.example.id + group = "example-group" +} + +resource "azurerm_kubernetes_fleet_update_run" "example" { + name = "example" + kubernetes_fleet_manager_id = azurerm_kubernetes_fleet_manager.example.id + managed_cluster_update { + upgrade { + type = "Full" + kubernetes_version = "1.27" + } + node_image_selection { + type = "Latest" + } + } + stage { + name = "example" + group { + name = "example-group" + } + after_stage_wait_in_seconds = 21 + } +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `name` - (Required) The name which should be used for this Kubernetes Fleet Update Run. Changing this forces a new Kubernetes Fleet Update Run to be created. + +* `kubernetes_fleet_manager_id` - (Required) The ID of the Fleet Manager. Changing this forces a new Kubernetes Fleet Update Run to be created. + +* `managed_cluster_update` - (Required) A `managed_cluster_update` block as defined below. + +* `fleet_update_strategy_id` - (Optional) The ID of the Fleet Update Strategy. Only one of `fleet_update_strategy_id` or `stage` can be specified. + +* `stage` - (Optional) One or more `stage` blocks as defined below. Only one of `stage` or `fleet_update_strategy_id` can be specified. + +--- + +A `managed_cluster_update` block supports the following: + +* `upgrade` - (Required) A `upgrade` block as defined below. + +* `node_image_selection` - (Optional) A `node_image_selection` block as defined below. + +--- + +A `upgrade` block supports the following: + +* `type` - (Required) Specifies the type of upgrade to perform. Possible values are `Full` and `NodeImageOnly`. + +* `kubernetes_version` - (Optional) Specifies the Kubernetes version to upgrade the member clusters to. This is required if `type` is set to `Full`. + +--- + +A `node_image_selection` block supports the following: + +* `type` - (Required) Specifies the node image upgrade type. Possible values are `Latest` and `Consistent`. + +--- + +A `stage` block supports the following: + +* `group` - (Required) One or more `group` blocks as defined below. + +* `name` - (Required) The name which should be used for this stage. + +* `after_stage_wait_in_seconds` - (Optional) Specifies the time in seconds to wait at the end of this stage before starting the next one. + +--- + +A `group` block supports the following: + +* `name` - (Required) The name which should be used for this group. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the Kubernetes Fleet Update Run. + +## 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 Kubernetes Fleet Update Run. +* `read` - (Defaults to 5 minutes) Used when retrieving the Kubernetes Fleet Update Run. +* `update` - (Defaults to 30 minutes) Used when updating the Kubernetes Fleet Update Run. +* `delete` - (Defaults to 30 minutes) Used when deleting the Kubernetes Fleet Update Run. + +## Import + +Kubernetes Fleet Update Runs can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_kubernetes_fleet_update_run.example /subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.ContainerService/fleets/fleet1/updateRuns/updateRun1 +```